Shell
shell是一种命令行解释器,它用来将用户指令翻译给内核,将内核结果翻译给用户。以降低使用成本,保护内核安全。
bash script.sh, ./script.sh, source script.sh,前两种执行方式是交给子进程执行可以隔离执行环境,后者作用于本次会话。
1. 变量
变量分类
shell中的变量有四种,分别是本地变量、环境变量、全局变量、系统变量。
| 类型 | 解释 |
|---|---|
| 本地变量 | 在shell中定义的普通变量,仅在本shell中有效 |
| 环境变量 | 环境变量对本shell以及子进程有效 |
| 全局变量 | 用户定义在配置文件内的变量,启动会话时会自动导入,执行顺序为profile, bash_profile, bashrc, bash_logout |
| 系统变量 | 系统定义的指定名称的变量,如SHELL,PWD,HOME,以及如下的特殊变量 |
| 特殊变量 | |
| $? | 值为上一条命令的返回状态 |
| $1-$9 | 用来获取命令行参数,$0表示脚本名,表示第一到第九的参数,十以上用$ |
| $# | 命令行参数的个数,不包含脚本名 |
| $* | 所有命令行参数,不包含脚本名,作为一个整体字符串 |
| $@ | 所有命令行参数,不包含脚本名,每个参数分开字符串 |
| $$ | 获取当前进程的父进程的PID |
自定义变量
| 自定义变量 | 方式 |
|---|---|
| 定义变量 | 变量名=值,赋值符左右不能有空格,默认是字符串类型 |
| 删除变量 | unset 变量名 |
| 定义只读变量 | readyonly 变量名=值,只读变量不可被unset |
| 导入环境变量 | export 变量名 |
| 定义环境变量 | export 变量名=值 |
| 根据类型定义变量 | declare -类型 变量名=值,-i 整型,-r 只读,-a 普通数组,-A 关联数组,-x 环境变量 |
2. 运算符
| 运算符 | 解释 |
|---|---|
| + - \* / % | \*表示乘号,**表示次幂 |
| expr | expr `expr 2 + 3` \* 4,运算符前后要求空格 |
| $(()) $[] | $(((2+3)*4)),$[(2+3)*4]) |
| let | let加整数运算表达式,let a++, let a+=1等 |
常用通配符
| 通配符 | 含义 | 解释 |
|---|---|---|
* | 匹配0或任意个字符 | |
? | 匹配单个字符 | |
[] | 匹配[]内任意单个字符 | [abc]表示该位置可以是a,b,c中的任意一个字符,[a-z]表示可以是a-z中的任意一个字符 |
[!] | 抛弃[]内任意单个字符 | |
{} | 匹配{}内的任意一组字符串 | {1,2,123},该位置可以是1,2,123 |
运算式的引号
| 引号 | 解释 |
|---|---|
| 双引号 " | 将引号内容当作整体,允许$引用其他变量 |
| 单引号 ' | 将引号内容当作整体,不允许引用其他变量,所有字符视为原始字符 |
| 反引号 ` | 和$()一致,将里面的命令或表达式优先执行 |
3. 条件
| 条件格式 | 解释 |
|---|---|
| test 条件,[ 条件 ] | 两种方式作用一致 |
| [[ 条件 ]] | 支持正则表达式 |
| 条件 | 解释 |
|---|---|
| 数值比较 | -lt 小于,-le 小于等于,-gt 大于,-ge 大于等于,-eq 等于,-ne 不等于 |
| (( )) 类C风格条件表达式 | |
| 文件类型 | -e 文件存在,-f 存在且为普通文件,-d 存在且为目录 |
| 文件权限 | -r 具有读权限,-w 具有写权限,-e 具有执行权限 |
| 文件新旧 | file1 -nt file2 file1比file2更新,-ot 更旧,-ef 是否为相同文件(同一个inode) |
| 字符串 | -z 为空,-n 非空,= 相等 != 不相等 |
| 逻辑与 | &&,-a |
| 逻辑或 | ||,-o |
4. 流程控制
4. 分支
if
shell
if [ $1 -lt $2 ]; then
echo "$1 -lt $2"
elif [ $1 -eq $2 ]; then
echo "$1 -eq $2"
else
echo "$1 -gt $2"
fishell
if [ $1 -lt $2 ]
then
echo "$1 -lt $2"
elif [ $1 -eq $2 ]
then
echo "$1 -eq $2"
else
echo "$1 -gt $2"
fishell
if [ cond1 ] && [ cond2 ]; then # 多个条件
ficase
shell
case $1 in
0)
echo 'female'
;;
1)
echo 'male'
;;
*)
echo 'unkown'
;;
esac5. 循环
for
shell
sum=0
for (( i=0; i < 3; i++)) # 类C风格循环
do
sum=$[$sum + $i]
done
echo $sumshell
for v in 1 2 3 4 # 列表循环
do
echo $v
done
for v in {1,2,3,4}
do
echo $v
doneshell
for v # 将命令行参数作为循环列表,等同于 for v in '"$@"'
do
echo $v
donewhile
shell
i=0
while [ $i -lt $1 ] # while :; 死循环
do
echo $i
i=$[$i+1]
doneuntil
shell
i=0
until [ $i -ge $1 ]
do
echo $i
let i++
doneshift
shift用于将参数列表向左移动一位,也就是删除第一个参数,后续参数向前移动。
位于整个文件就是作用于命令行参数,位于函数内就是作用于函数参数。
shell
echo $*
shift
echo $*
function test_shift() {
echo $*
shift
echo $*
}
test 1 2 3 4 5expect
expect用来代替用户的交互行为,做到自动化,通常作用于交互式的程序中。
shell
#!/bin/expect
set sip "localhost"
set user "yyx"
set pswd "YYXyyx123456"
spawn ssh $user@$sip
expect {
"yes/no" { send "yes\r"; exp_continue }
"password" { send "$pswd\r" }
}
expect "$"
send "date\r"5. 输入输出
| 命令 | 解释 |
|---|---|
| read | 标准输入读取,-p 打印提示,-t 等待事件,-s 输入不回显,搭配<读取文件内容 |
| echo | 标准输出打印,-e 内含转义字符,-n 禁止自动换行 |
6. 函数
函数分为系统函数和自定义函数。
| 系统函数 | 解释 |
|---|---|
| basename string [suffix] | 截取出路径最后的文件名,指定后缀后也可截去后缀 |
| dirname string | 截取出路径的目录部分,结果不以/结尾 |
shell
function funcname()
{
statement
return
}- 函数返回值只能通过 $? 获得。如果函数最后没有return,则以最后一条命令的运行结果作为函数返回值。
- 在函数内部,$1 $2 仅代表函数参数,不会和命令行参数冲突。
7. 数组
shell的数组有两种:
- 普通数组:只能使用整数作为数组下标。
- 关联数组:可以使用字符串作为数组下标,本质是哈希。
| 普通数组定义 | 解释 |
|---|---|
| arr[0]=xx; arr[1]=xx; ... | 定义然后添加元素 |
| arr=(v1 v2 v3 ...) | 定义并初始化 |
| arr=(`ls`) | 将命令结果按空格或换行分割,并作为数组元素 |
| 普通数组获取元素 | 解释 |
|---|---|
| $ | 按下标获取数组元素 |
| ${arr[*]} $ | 获取所有元素 |
| $ | 获取数组元素个数 |
| $ | 获取数组元素下标 |
| $ | 根据起始位置和偏移量,获取部分数组元素 |
| 关联数组定义 | 解释 |
|---|---|
| declare -A arr; arr[str]=xx; ... | 定义然后添加元素 |
| declare -A arr; arr=([str]=xx ...) | 定义并初始化 |
| 关联数组获取元素 | 解释 |
|---|---|
| $ | 获取数组元素 |
| ${arr[*]} $ | 获取所有元素 |
| $ | 获取数组元素个数 |
| $ | 获取数组元素下标 |
8. 文本处理
| 命令 | 解释 |
|---|---|
| grep string file | 行过滤,-v 反向过滤,-n打印行号,-i忽略大小写,-B 指定头几行,-A 尾几行,-C 头尾几行 |
| cut -f int -d string file | 列过滤,-f 指定列号,-d 指定分割符默认为\t |
| sort | 行排序,-u 去重,-r 降序默认升序,-n 按数字排序,-k 按指定列排序,-t 分隔符,-o 结果输出文件 |
正则表达式中,^和$分别表示行首和行尾,^abc表示以abc开头,abc$表示以abc结尾。
sed
sed是流文本编辑器,就是将文件按行处理,shell脚本中使用sed来精准修改文件。
| 选项 | 解释 |
|---|---|
-e | 指定脚本表达式,也就是对文本的处理方法。脚本中不指定行表示对所有行生效。 |
增:分为行前新增和行后追加,i表示行前新增,a表示行后追加。 | |
删:d表示删除整行。 | |
改:分为覆盖整行和替换部分,c表示覆盖整行,s表示替换部分。 | |
查:p表示查看。 | |
-i | 默认不会修改源文件,-i表示将结果输出到源文件,-i跟内容表示修改并生成备份文件,-i内容是备份文件名的后缀。 |
-n | -n '1p':忽略缓冲区,仅打印文件的第一行内容。 |
-f | -e是手写脚本,-f是指定sed脚本文件 |
shell
sed -e '1i\first line' test.txt # 第一行前新增一行first line
sed -e '1a\second line' test.txt # 第一行后追加一行second line
sed -i -e '1i\first line' test.txt # 将结果输出到源文件
sed -i.bk -e '1i\first line' test.txt # 修改源文件之前生成一份备份文件,名为test.txt.bk
sed '1d' test.txt # 删除第一行
sed '1c\first line' test.txt # 修改第一行为first line
sed '1s/1/2/' test.txt # 第一行的1替换成2,只查找替换一次
sed '1s/1/2/g' test.txt # 第一行中全部的1都替换成2
sed -n '1p' test.txt # 忽略缓冲区,仅打印文件的第一行内容