Shell脚本
一、变量
1.1 变量赋值
- 直接赋值
#!/bin/bash
name="tanqing"
declare -i num=123 #声明整数型变量
declare -a lists=("a" "b" "c") #定义数组
- 间接赋值
#!/bin/bash
read -p "please insert a num: " num
echo $num
1.2 命令替换
将命令执行的结果保存给变量,需要做命令替换,有如下两种方式
#!/bin/bash
#Step1
num1=10
num2=20
sum=`expr $num1 + $num2`
#Step2
num1=10
num2=20
sum=$(expr $num1 + $num2)
1.3 内置变量
| 内置变量 | 作用 |
|---|---|
| $0 | 脚本名 |
| $1-$10 | 位置参数1-10 |
| $# | 传递位置参数的总个数 |
| $@ | 所有位置参数(每个作为单独字符串) |
| $* | 所有位置参数(作为单个字符串) |
| $? | 返回值 |
| $$ | 脚本进程的PID |
二、数值运算
- 方法1
#!/bin/bash
num1=10
num2=20
sum=$(($um1+$num2))
echo $sum
- 方法2
#!/bin/bash
num1=10
num2=20
sum=$(expr $num1 + $num2) #注意运算符两边必须有空格
echo $sum
- 方法3
#!/bin/bash
num1=10
num2=20
let sum=$num1+$num2 #注意运算符两边不能有空格
echo $sum
三、条件测试
- 测试方法
# [ -f /var/log/message ] #中括号测试
# test -f /var/log/message # test关键字测试
- 测试变量
| 选项 | 说明 |
|---|---|
| -f | 测试指定文件是否存在 |
| -d | 测试指定目录是否存在 |
| -e | 测试指定目录/文件是否存在 |
| -z | 测试字符串长度是否为0 |
| $ | 测试字符串长度是否为0 |
| -n | 测试字符串长度是否不为0 |
| -S | 测试指定文件是否是Socket文件 |
| -w | 测试文件是否有写权限 |
| -r | 测试文件是否有读权限 |
| -x | 测试文件是否有执行权限 |
| -L | 测试文件是否是一个链接文件 |
四、运算符
- 算数运算符
| 运算符 | 说明 |
|---|---|
| + | 加法 |
| - | 乘法 |
| * | 乘法 |
| / | 除法 |
| % | 取模 |
- 关系运算符
| 运算符 | 说明 |
|---|---|
| =,==,-eq | 是否相等 |
| -ne,!= | 是否不相等 |
| -ge | 是否大于等于 |
| -gt | 是否大于 |
| -le | 是否小于等于 |
| -lt | 是否小于 |
- 逻辑运算符
| 运算符 | 说明 |
|---|---|
| -a | and,表示前面和后面的表达式都为真才为真 |
| -o | or,表时前面或后面的表达式有一个为真既为真 |
| && | 逻辑与,前面命令执行成功,执行后面的命令 |
| || | 逻辑非,前面命令执行失败,执行后面的命令 |
| ; | 前面命令执行完毕,执行后面的命令 |
五、流程控制
5.1 if判断
- if 单分支
#!/bin/bash
num1=10
num2=20
if [ $num2 -ge $num1 ];then
echo "$num2大于${num1}."
else
echo "$num2小于${$num1}"
fi
- if 多分支
#!/bin/bash
num1=10
if [ $num1 -gt 100 ];then
echo "$num1大于100"
elif [ $num1 -gt 50 ];then
echo "$num1大于50"
elif [ $num1 -gt 10 ];then
echo "$num1大于10"
else
echo "$num1小于10"
fi
5.2 case判断
#!/bin/bash
#
case 变量 in
start)
命令;;
stop)
命令;;
restart)
命令;;
status
命令;;
*)
命令;;
esac
case 支持 glob 风格的通配符:
*:任意长度的任意字符;
?:任意单个字符;
[ ]:范围内任意单个字符;
a|b:a 或 b;
5.3 for循环
#!/bin/bash
#step1
for i in `seq 1 10`;do
echo "$i"
done
#step2
for i in {1..10};do
echo "$i"
done
#step3
for i in 1 2 3 4 5 6 7 8 9 10;do
echo "$i"
done
5.4 while循环
#!/bin/bash
#step1 死循环
while true;do
echo "死循环."
done
#step2 跳出循环
i=0
while [ $i -lt 10 ];do
let i++
if [ $i -eq 5 ];then
continue
fi
echo "$i"
done
#step 中止循环
i=0
while [ $i -lt 10 ];do
let i++
if [ $i -eq 5 ];then
break
fi
echo "$i"
done
六、数组
- 普通数组定义:
declare -a myarray - 关联数组定义:
declare -A myarray - 数组引用:
${myarray[index]}
6.1 数组赋值
# ARRAY_NAME[INDEX]=value #一次只赋值一个元素
# ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...) #一次赋值多个元素
# ARRAY_NAME=([0]="VAL1" [3]="VAL4" ...) #赋值不连续的索引,稀疏格式
注意:bash-4及之后的版本,支持自定义索引格式,而不仅仅是0,1,2,...数字格式;此类数组称之为“关联数组”

6.2 数组的操作
- 取数组长度:
${#ARRAY_NAME[*]},${#ARRAY_NAME[@]} - 引用数组中的所有元素:
${ARRAY_NAME[*]},${ARRAY_NAME[@]} - 数组切片:
${ARRAY_NAME[@]:offset:number}
offset:要跳过的元素个数,起始元素位置;
number:要取出的元素个数;省略number时,表示取偏移量之后的所有元素;

- 追加元素:
ARRAY_NAME[${#ARRAY_NAME[*]}]=VALUE元素的索引为元素的长度 - 删除元素:
unset ARRAY[INDEX]
七、信号捕捉
进程在运行的时候,我们可以对进程发送信号来控制进程,信号有很多种,如中止、结束、挂起、重载等,在脚本运行过程中,也有可能因为误操作或者其他异常情况导致脚本中断运行,我们可能在进程中止前做一些特定操作,就需要用到信号捕捉。
- 查看所有信号:
kill -l;trap -l - 捕捉信号:
trap "捕捉到信号后执行的命令" 信号
下列代码正常执行完会删除临时文件,但如果被用户按CTRL+C中止,则不会执行rmtmp函数,而当信号捕捉到SIGINT信号(CTRL+C)时,执行rmtmp函数。
#!/bin/bash
declare -a tmpfiles
function rmtmp(){
rm -f ${tmpfiles[@]}
echo "删除临时文件完毕"
}
trap 'rmtmp' SIGINT
for i in {1..10};do
sleep 1;
tmp_file=`mktemp /tmp/test.XXXX`;
echo "$i" | tee $tmp_file;
tmpfiles[${#tmpfiles[*]}]=$tmp_file
done
rmtmp
八、字符串处理
- 字符串切片:
${var:offset:number},和数组切片一致

8.1 查找替换
- 替换一次:
${var/oldstr/newstr}查找var所表示的字符串中,将第一次匹配到的字符串替换。
[root@dayet ~]# str="This is test str. test test test ~"
[root@dayet ~]# echo "${str/test/TEST}"
This is TEST str. test test test ~
- 全局替换:
${var//oldstr/newstr}查找var所表示的字符串中,将所有匹配到的字符串替换。
[root@dayet ~]# str="This is test str. test test test ~"
[root@dayet ~]# echo "${str//test/TEST}"
This is TEST str. TEST TEST TEST ~
- 行首匹配替换:
${var/#oldstr/newstr}:查找var所表示的字符串中,将行首被oldstr所匹配到的字符串替换。
[root@dayet ~]# str="root:x:0:0:root:/root:/bin/bash"
[root@dayet ~]# echo ${str/#root/ROOT}
ROOT:x:0:0:root:/root:/bin/bash
- 行首匹配替换:
${var/%oldstr/newstr}:查找var所表示的字符串中,将行尾被oldstr所匹配到的字符串替换。
[root@dayet ~]# str='This is test . test test test'
[root@dayet ~]# echo ${str/%test/TEST}
This is test . test test TEST
- 查找删除:newstr处为空即可。
8.2 模式匹配提取字符串
${var#*word}:其中word是指定的分隔符;从左向右查找var变量所存储的字符串中,第一次出现的word分隔符,删除字符串开头到分隔符之间的所有字符;

${var##*word}:其中word是指定的分隔符;从左向右查找var变量所存储的字符串中,最后一次出现的word分隔符,删除字符串开头到分隔符之间的所有字符;

${var%word*}:其中word是指定的分隔符;从右向左查找var变量所存储的字符串中,第一次出现的word分隔符,删除此分隔符到字符串尾部之间的所有字符;

${var%%word*}:其中word是指定的分隔符;从右向左查找var变量所存储的字符串中,最后一次出现的word分隔符,删除此分隔符到字符串尾部之间的所有字符;

8.3 大小写转换
${var^^}:把var中的所有小写字符转换为大写;

${var,,}:把var中的所有大写字符转换为小写;

九、函数
- 函数定义
#!/bin/bash
function test(){
echo "This is test function"
}
test
- 函数调用:直接输入函数名就行,不用加()
- 函数传参:函数内接收参数的变量是$1,$2,$3...,和脚本运行的的位置变量同名,因此在函数内如果要接收shell位置参数需要将位置变量保存到全局变量中。
#!/bin/bash
name=$1
function say_hello(){
echo "hello,$1"
}
say_hello $name
- 函数返回值:用return关键字
十、重定向
命令的输出分为标准输出(1)和错误输出(2),默认只重定向标准输出。
| 示例 | 说明 |
|---|---|
| > | 覆盖重定向,会将源文件内容清空 |
| >> | 追加重定向 |
| command 1> a.txt | 标准输出重定向 |
| command > a.txt | 标准输出重定向 |
| command 2> a.txt | 错误输出重定向 |
| command > a.txt 2>&1 | 标准输出和错误输出都重定向,2&1表示错误输出等于于标准输出 |
| command 1>a.txt 2>a.txt | 标准输出和错误输出都重定向 |
| >/dev/null | 将标准输出屏蔽 |
| >/dev/null | 将错误输出屏蔽 |
| &> a.txt | 正确输出和错误输出都重定向 |

浙公网安备 33010602011771号