Shell编程基础
变量
定义、使用、删除
- 定义变量 - 定义时不加$符号
- 变量名和等号之间不能有空格
- 变量名只能由英文字母、数字、下划线,且不以数字开头, 不能用bash中的关键字
- 已经定义变量可以重新定义
 
- 定义时不加
- 使用变量 - 即可使用, 未定义变量直接使用不报错,返回空值
- {}可选,但是- {}能够明确定义变量名范围,帮助阅读、 解释器执行
 
- 匿名变量 - 可以认为所以语句(命令)的执行结果都存储在一个匿名
变量中,可以在其之前加上$获取其结果
 
- 可以认为所以语句(命令)的执行结果都存储在一个匿名
变量中,可以在其之前加上
- readonly:设置变量为只读变量,更改(重定义)变量报错
- unset:删除变量,不能删除只读变量
局部变量
局部变量:在脚本、命令中定义
- 仅在当前shell实例中有效 - shell变量默认为global,作用域从被定义处开始到脚本 末尾(即使在函数内部定义)
- 显式local声明作用域局限于函数内部
 
- 其他shell启动的程序不能访问局部变量 
环境变量
环境变量:就是shell中的普通变量,只是这些变量往往被进程读取 用于自身初始化、设置
- 狭义:export/declare -x声明的变量,只有这样的变量 才能默认被子进程继承
- 广义;shell中所有的变量(包括局部变量)
环境变量设置
在shell中设置环境变量有两种方式
- export/- declare -x:设置全局(环境)变量- 任何在该shell设置环境变量后,启动的(子)进程都会 继承该变量
- 对于常用、许多进程需要的环境变量应该这样设置
 
- <ENV_NAME>=... cmd:设置临时环境变量- <ENV_NAME>=...不能被子进程继承,所以必须在其后立刻 接命令
- 只对当前语句有效,也不能覆盖同名变量
 
用途
- 环境变量是某些程序正常运行的必要条件
- 所有程序都能访问环境变量,可用作进程通信- 在程序中设置环境变量,供其他进程访问变量
- 父进程为子进程设置环境变量,供其访问
 
Shell变量
Shell变量:shell程序设置的特殊变量,包括环境变量、局部变量, 保证shell的正常运行
- $0:shell执行脚本名- 交互式bash(即普通终端中)该参数为-bash- 则source执行脚本时,该参数可能非预期
 
- 则
- 以下shell变量均不考虑$0,如- 函数中$0也是脚本名
- shift无法跳过该参数
 
- 函数中
 
- 交互式bash(即普通终端中)该参数为
- $1,..., $9:向脚本传递的位置参数
- $@:脚本、函数参数列表
- $*:脚本、函数参数字符串
- $#:脚本、函数参数数量
- $?:上条命令执行结果
- $$$$:脚本进程号
- $!:执行脚本最后一条命令
字符串
拼接
- shell中字符默认为字符串,自动拼接
通配符
- *:匹配任意长度字符串- 不包括.、/,必须显式匹配
 
- 不包括
- ?:匹配一个字符
- []:匹配出现在- []中的字符- 1 
 2- ls /[eh][to][cm]* 
 匹配`/etc`、`/home`等
- {}- 枚举全部 - 1 
 2
 3
 4
 5
 6- mkdir {user1, user2}-{home, bin} 
 笛卡尔积(字符串连接)
 等价于建立`user1-home, user1-bin, user2-home, user2-bin`
 echo {1..10}
 生成序列
 见`for`中`RangeIterator`部分
 
子串
| 1 | file=/dir1/dir2/dir3/file.txt.bak | 
切片
- ${<var_name>:n[:m]}:从第- n开始- m个字符- n、- m非负值- n:从0开始的下标起始
- m:切片长度,缺省表示到末尾
 
- n、- m使用- 0-负值表示- n:从0开始的负向下标起始
- m:从0开始的负向下标终止
 
 
| 命令 | 解释 | 结果 | 
|---|---|---|
| ${file:0:5} | 提取首个字符开始的5个字符 | /dir1 | 
| ${file:5:5} | 提取第5个字符开始的5个字符 | /dir2 | 
| ${file:5} | 提取第5个字符开始至末尾 | /dir2... | 
| ${file:0-5} | 反向计算下标 | t.bak | 
| ${file:0-5:0-1} | 反向计算下标 | t.ba | 
| ${file:5:0-2} | 提取第5个字符开始至 -2下标处 | /dir2.../t.b | 
子串匹配
| 1 | {<var_name>%<pattern>} | 
- #:去掉字符串左边最短pattern
- ##:去掉字符串左边最长pattern
- %:去掉字符串右边最短pattern
- %%:去掉字符串右边最长pattern
- 注意:
var_name前不要变量标志$- 以上4种模式返回新值,不改变原变量值
- 仅在
pattern中使用通配符时,最短、最长匹配才有区别
| 命令 | 解释 | 结果 | 
|---|---|---|
| ${file#*/} | 去除首个 /及其左边 | dir2/dir3/file.txt.bak | 
| ${file##*/} | 仅保留最后 /右边 | file.txt.bak | 
| ${file#*.} | 去除首个 .及其左边 | txt.bak | 
| ${file##*.} | 仅保留最后 .右边 | bak | 
| ${file%/*} | 去除最后 /及其右边 | /dir1/dir2/dir3 | 
| ${file%%*/} | 去除首个 /及其右边 | 空值 | 
| ${file%*.} | 去除最后 .及其右边 | /dir1/dir2/dir3/file.txt | 
| ${file%%*.} | 去除首个 .及其右边 | /dir1/dir2/dir3/file.txt | 
替换
- /from/to:替换首个- from为- to
- //from/to:替换全部- from为- to
| 命令 | 解释 | 结果 | 
|---|---|---|
| ${file/dir/path} | 替换首个 dir为path | /path1/dir2/dir3/file.txt.bak | 
| ${file/dir/path} | 替换全部 dir为path | /path1/path2/path3/file.txt.bak | 
默认值替换
- -:变量未设置返回
- +:变量设置返回
- =:变量未设置返回、设置变量
- ?:变量未设置输出至stderr
- ::以上命令条件包括空值(空值视为未设置)

| 命令 | 解释 | 示例 | 结果 | 
|---|---|---|---|
| ${井<var_name>} | 获取字符串长度 | ${井file} | 27 | 
| ${<var_name>-<default>} | 变量未设置返回默认值 | ${invalid-file.txt.bak} | file.txt.bak | 
| ${<var_name>:-<default>} | 变量未设置、空值返回默认值 | ${null-file.txt.bak} | file.txt.bak | 
| ${<var_name>+<default>} | 变量设置返回默认值 | ${file-file.txt.bak} | fil.txt.bak | 
| ${<var_name>:+<default>} | 变量非空返回默认值 | ${file-file.txt.bak} | file.txt.bak | 
| ${<var_name>=<default>} | 变量未设置,返回默认值、并设置变量为默认值 | ${invalid=file.txt.bak} | file.txt.bak | 
| ${<var_name>:=<default>} | 变量未设置、空值返回默认值、并设置变量为默认值 | ${null=file.txt.bak} | file.txt.bak | 
| {$<var_name>?<default>} | 变量未设置输出默认值至stderr | {invalid?file.txt.bak} | file.txt.bak输出至stderr | 
| {$<var_name>:?<default>} | 变量未设置、空值输出默认值至stderr | {$null:?file.txt.bak} | file.txt.bak输出至stderr | 
字符串比较
- =, !=, -z, -n:字符串相等、不相等、为空、非空
- 使用 - =比较变量是否为某字符串时,其中在两侧添加字符 保证- =不为空值,否则若- $test为空值,表达式报错- 1 
 2
 3- if [[ "$text"x = "text"x ]]; then 
 command
 fi
- 比较变量时要在两侧加上双引号
"",否则可能报错、结果不 符合预期
数组
| 1 | A=(a b c def) | 
取值
- []:选择数组元素- [n]:返回数组第n个元素
- [*]/- [@]:返回数组全部元素
 
| 命令 | 解释 | 结果 | 
|---|---|---|
| ${A[@]} | 返回全部元素 | a b c def | 
| ${A[*]} | 同上 | 同上 | 
| ${A[0]} | 返回数组第一个元素 | a | 
| ${井A[@]} | 返回数组元素总数 | 4 | 
| ${井A[*]} | 同上 | 同上 | 
| ${井A[3]} | 返回数组第4个元素长度 | 3 | 
| A[3]=xyz | 设置数组第4个元素值 | 
数值
- (())/- []:在其中执行整数运算
- let:执行数值运算
规则
- 返回的数据结果相当于存储在一个匿名变量中,使用的话需要 在之前加上 - $
- 1 
 2
 3- a=5; b=7; c=2; 
 echo $((a + b * $c))
 19
- $((N#xx))/- $[$#xx]:将其他进制数据转换为10进制- 1 
 2- echo $((2#110)) 
 6
- 自增、自减运算可以在 - (())/- []中直接执行- 1 
 2- a=5; ((a++)); echo $a; 
 6
特殊运算符
- ~:位与
- |:位或
- ^:位异或
- >>:位右移
- <<:位左移
- **:数值平方
- +=, ++, -=, --, *=, \=:自变化运算符
逻辑运算
- -eq, -ne, -ge, -le, -lt, -gt:比较
- ==, !=, >=, <=, <, >:数值比较
文件
- -e:目标存在
- -f:文件为一般文件(非目录、设备)
- -s:文件大小非0
- -d:目标为目录
- -b:文件为块设备(软盘、光驱)
- -c:文件为流设备(键盘、modem、声卡)
- -p:文件为管道
- -h/- L:目标为符号链接
- -S:目标为Socket
- -t:文件描述符被关联到终端- 一般用于检测脚本的stdin是否来自终端[ -t 0 ],或 输出是否输出至终端[ -t 1 ]
 
- 一般用于检测脚本的stdin是否来自终端
- -r:目标是否可读权限
- -w:目标是否可写权限
- -x:目标是否可执行权限
- -g:目标是否设置有set-group-id
- -u:目标是否设置有set-user-id
- -k:目标是否设置sticky bit
- -O:用户是否是文件所有者
- -G:用户是否属于文件所有组
- -N:文件从上次读取到现在为止是否被修改
- f1 -nt f2:文件- f1比- f2新
- f1 -ot f2:文件- f1比- f2旧
- f1 -ef f2:文件- f1、- f2指向相似文件实体(相同的硬链接)

