一、Shell编程之条件结构
1、Shell条件测试语法、
test测试表达式 | 利用test命令进行条件测试表达式,test命令与测试表达式之间至少一个空格 |
[ 测试表达式 ] | 通过[ ]中括号进行条件表达式,[ ]中括号边界与测试表达式之间至少一个空格 |
[[ 测试表达式 ]] | 通过[[ ]]双中括号进行条件测试表达式,[[ ]]双中括号与测试表达式之间至少有一个空格 |
((测试表达式)) | 通过(( ))双小括号进行条件测试表达式,( ))双小括号两端不需要空格,常用于整数对比 |
1、符号说明
符号 | 作用 |
(()) | 数值比较,运算 C语言 |
[[]] | 条件测试,支持正则 |
$(()) | 整数运算 |
$[] | 整数运算 |
$() | 命令替换 shell会先执行括号的cmd,然后将结果作为变量进行替换,替换只能替换标准输出,错误输出不能 替换。 `` |
${} | Shell中变量的原形,用于限定变量名称的范围,并且支持通配符 |
[] | 条件测试 |
() | 子shell中执行 |
{} | 在当前 shell 执行 |
[root@hostname ~]# var=test [root@hostname ~]# echo var var [root@hostname ~]# echo $var test [root@hostname ~]# (var=notest;echo $var) notest [root@hostname ~]# {var=notest;echo $var} {var=notest: command not found test} [root@hostname ~]# {var=notest;echo $var;} ‐su: syntax error near unexpected token `}' [root@hostname ~]# { var=notest;echo $var;} notest [root@hostname ~]# echo $var notest # {}修改了变量的值。表明在当前shell中运行的 [root@hostname ~]# var=test [root@hostname ~]# echo $var test [root@hostname ~]# (var=notest;echo $var) notest [root@hostname ~]# echo $var test # ()里的执行完毕后没有改变变量的值,说明在子shell中执行的 # $(( ))和$[ ]的用途一致,用来作整数运算。在 bash 中,$(( ))的整数运算符号大致有这些: # + ‐ * / 加、减、乘、除 # % 余数运算 # & | ^ ! AND、OR、XOR、NOT运算 举例: [root@hostname ~]# a=5; b=7; c=2 [root@hostname ~]# echo $((a+b*c)) [root@hostname ~]# echo $[a+b*c] 19 [root@hostname ~]# echo $(((a+b)/c)) [root@hostname ~]# echo $[(a+b)/c] 6 [root@hostname ~]# echo $(((a*b)%c)) [root@hostname ~]# echo $[(a*b)%c] 1 # $(( ))中的变量名称也可以在其前面加 $ 符号:$(($a+$b*$c))也可以得到 19 的结果。 # $(( ))还可以作不同进制(如二进制、八进位、十六进制)运算,只是输出结果皆为十进制而已。 [root@hostname ~]# echo $((16#2a)) # 16进位转十进制 42 # 当前的 umask 是 022,新建文件的权限为: [root@hostname ~]# umask 022 [root@hostname ~]# echo "obase=8; $(( 8#666 & (8#777 ^ 8#$(umask)) ))" | bc [root@hostname ~]# 644 # 单纯用(( ))也可以重定义变量值,或作testing: [root@hostname ~]# a=5 [root@hostname ~]# echo $((a++)) # 将 a 重定义为 6 [root@hostname ~]# echo $[a‐‐] [root@hostname ~]# 5 [root@hostname ~]# echo $((a‐‐)) [root@hostname ~]# 4 [root@hostname ~]# a=5; b=7; ((a < b));echo $? 0 # 常见的用于(( ))的测试符号有以下这些:< 小于,> 大于,<= 小于或等于,>= 大于或等于,== 等于,!= 不等于
- 双中括号[[ ]]中可以使用通配符进行匹配,这是其区别于其它几种语法的地方
- &&,||,<,>等操作符可用于双中括号[[ ]]中,但不能应用于[ ]中,在[ ]中一般用-a,-o,-lt,-gt来代替
- 备注: -a and -o or
[root@hostname ~]# test ‐f /tmp/test.txt && echo 1 || echo 0 [root@hostname ~]# [ ‐f /tmp/test.txt ] && echo 1 || echo 0 [root@hostname ~]# [[ ‐f /tmp/test.txt ]] && echo 1 || echo 0 [root@hostname ~]# ((3>2)) && echo 1 || echo 0
2、Shell 测试表达式用法
1、文件测试表达式
-d 文件 | 文件存在且为目录则为真 |
-f 文件 | 文件存在且为普通文件则为真 |
-s 文件 | 文件存在且文件大小不为0则为真 |
-r 文件 | 文件存在且可读则为真,与执行脚本的用户权限也有关 |
-w 文件 | 文件存在且可写则为真,与执行脚本的用户权限也有关 |
-x 文件 | 文件存在且可执行则为真,与执行脚本的用户权限也有关 |
- L 文件 | 文件存在且为链接文件则为真 |
f1 -nt f2 | 文件f1比文件f2新则为真,根据文件的修改时间计算 |
f1 -ot f2 | 文件f1比文件f2旧则为真,根据文件的修改时间计算 |
-e 文件 | 文件存在则为真,不辩别是目录还是文件 |
[root@hostname ~]# test ‐d /home [root@hostname ~]# echo $? 0 [root@hostname ~]# test ‐d /home11111 [root@hostname ~]# echo $? 1 [root@hostname ~]# [ ‐d /home ] [root@hostname ~]# [ ! ‐d /ccc ] && mkdir /ccc [root@hostname ~]# [ ‐d /ccc ] || mkdir /ccc
2、字符串测试表达式
参数 | 功能 | |
-z | s1 | 如果字符串s1的长度为0,则测试条件为真 |
-n | s1 | 如果字符串s1的长度大于0,则测试条件为真 |
sl | 如果字符串s1不是空字符串,则测试条件为真 | |
=或== | s1 = s2 | 如果s1等于s2,则测试条件为真,“=”前后应有空格 |
!= | s1!=s2 | 如果s1不等于s2,则测试条件为真 |
< | s1 | 如果按字典顺序s1在s2之前,则测试条件为真 |
> | s1>s2 | 如果按自定顺序s1在s2之后,则测试条件为真 |
- 对于字符串的比较,一定要将字符串加比引号后再比较。如[ -n "$string" ]
- =与!=可用于判断两个字符串是否相同
- 字符串比较:
# 提示:字符串必须使用双引号 [root@hostname ~]# [ "$USER" = "root" ];echo $? 0 [root@hostname ~]# [ "$USER" == "root" ];echo $? 0 [root@hostname ~]# BBB="" [root@hostname ~]# echo ${#BBB} 0 [root@hostname ~]# [ ‐z "$BBB" ] # 字符长度是为0 [root@hostname ~]# echo $? 0 [root@hostname ~]# [ ‐n "$BBB" ] # 字符长度不为0 [root@hostname ~]# echo $? 1 [root@hostname ~]# var1=111 [root@hostname ~]# var2= [root@hostname ~]# # var3变量没有定义 [root@hostname ~]# echo ${#var1} 3 [root@hostname ~]# echo ${#var2} 0 [root@hostname ~]# echo ${#var3} 0 [root@hostname ~]# [ ‐z "$var1" ];echo $? 1 [root@hostname ~]# [ ‐z "$var2" ];echo $? 0 [root@hostname ~]# [ ‐z "$var3" ];echo $? 0 [root@hostname ~]# [ ‐n "$var1" ];echo $? 0 [root@hostname ~]# [ ‐n "$var2" ];echo $? 1 [root@hostname ~]# [ ‐n "$var3" ];echo $? 1
3、整数操作符
在[]和test中使用 | 在[[ ]]和(( ))中使用 | 说明 |
-eq | ==或= | 等于,全拼为equal |
-nq | != | 不等于,全拼为not equal |
-gt | > | 大于,全拼为greater than |
-ge | >= | 大于等于,全拼为greater equal |
-lt | < | 小于,全拼为less than |
-le | <= | 小于等于,全拼为less equal |
[root@hostname ~]# num10=123 [root@hostname ~]# num20=ssss1114ss [root@hostname ~]# [[ "$num10" =~ ^[0‐9]+$ ]];echo $? 0 [root@hostname ~]# [[ "$num20" =~ ^[0‐9]+$ ]];echo $? 1 [root@hostname ~]# num10=123 [root@hostname ~]# num20=ssss1114ss [root@hostname ~]# [[ "$num10" =~ ^[0‐9]+$ ]];echo $? 0 [root@hostname ~]# [[ "$num20" =~ ^[0‐9]+$ ]];echo $? 1
[root@hostname ~]# disk_use=$(df ‐P |grep '/$' |awk '{print $5}' |awk ‐F% '{print $1}') [root@hostname ~]# [ $disk_use ‐gt 90 ] && echo "war......" [root@hostname ~]# [ $disk_use ‐gt 60 ] && echo "war......" war...... [root@hostname ~]# id ‐u 0 [root@hostname ~]# [ $(id ‐u) ‐eq 0 ] && echo "当前是超级用户" 当前是超级用户 [alice@hostname ~]$ [ $UID ‐eq 0 ] && echo "当前是超级用户" || echo "you不是超级用户" you不是超级用户 [root@hostname ~]# disk_use=$(df ‐P |grep '/$' |awk '{print $5}' |awk ‐F% '{print $1}') [root@hostname ~]# [ $disk_use ‐gt 90 ] && echo "war......" [root@hostname ~]# [ $disk_use ‐gt 60 ] && echo "war......" war...... [root@hostname ~]# id ‐u 0 [root@hostname ~]# [ $(id ‐u) ‐eq 0 ] && echo "当前是超级用户" 当前是超级用户 [alice@hostname ~]$ [ $UID ‐eq 0 ] && echo "当前是超级用户" || echo "you不是超级用户" you不是超级用户
[root@hostname ~]# ((1<2));echo $? 0 [root@hostname ~]# ((1==2));echo $? 1 [root@hostname ~]# ((1>2));echo $? 1 [root@hostname ~]# ((1>=2));echo $? 1 [root@hostname ~]# ((1<=2));echo $? 0 [root@hostname ~]# ((1!=2));echo $? 0 [root@hostname ~]# ((`id ‐u`>0));echo $? 1 [root@hostname ~]# (($UID==0));echo $? 0
# 案例1: [root@hostname ~]# cat test02.sh #!/bin/bash # 判断用户输入的是否是数字 read ‐p "请输入一个数值: " num if [[ ! "$num" =~ ^[0‐9]+$ ]];then echo "你输入的不是数字,程序退出!!!" exit fi echo ccc # 案例2: [root@hostname ~]# cat test03.sh # !/bin/bash # 判断用户输入的是否是数字 read ‐p "请输入一个数值: " num while : do if [[ $num =~ ^[0‐9]+$ ]];then break else read ‐p "不是数字,请重新输入数值: " num fi done echo "你输入的数字是: $num"
4、逻辑操作符
在[]test中使用 | 在[[]]中使用 | 说明 |
-a | && | and,与,两端都为真,则结果为真 |
-o | || | or,或,两端有一个为真,则结果为真 |
! | ! | not,非,两端相反,则结果为真 |
[root@qfedu.com ~]# [ 1 ‐lt 2 ‐a 5 ‐gt 10 ];echo $? 1 [root@qfedu.com ~]# [ 1 ‐lt 2 ‐o 5 ‐gt 10 ];echo $? 0 [root@qfedu.com ~]# [[ 1 ‐lt 2 && 5 ‐gt 10 ]];echo $? 1 [root@qfedu.com ~]# [[ 1 ‐lt 2 || 5 ‐gt 10 ]];echo $? 0
5、测试表达式的区别总结
- 变量为空或者未定义长度都为
[root@hostname ~]# [ "$USER" = "root" ];echo $? 0 [root@hostname ~]# [ "$USER" = "alice" ];echo $? 1 [root@hostname ~]# [ "$USER" != "alice" ];echo $? 0 [root@hostname ~]# [ "$USER" = "root" ];echo $? 0 [root@hostname ~]# [ "$USER" =~ ^r ];echo $? bash: [: =~: binary operator expected 2 [root@hostname ~]# [[ "$USER" =~ ^r ]];echo $? # 使用正则 0
- Shell脚本执行测试
[root@hostname ~]# [ "$USER" = "root" ];echo $? 0 [root@hostname ~]# [ "$USER" = "alice" ];echo $? 1 [root@hostname ~]# [ "$USER" != "alice" ];echo $? 0 [root@hostname ~]# [ "$USER" = "root" ];echo $? 0 [root@hostname ~]# [ "$USER" =~ ^r ];echo $? bash: [: =~: binary operator expected 2 [root@hostname ~]# [[ "$USER" =~ ^r ]];echo $? # 使用正则 0
3、Shell 分支if语句
1、单分支if条件语句
if [ 条件判断式 ];then 条件成立时,执行的程序 fi # if语句使用fi结尾和一般语言使用大括号结尾不同 # [条件判断式] 就是使用test命令判断,所以中括号和条件判断式之间必须有空格 # then 后面跟符号条件之后执行的程序,可以放在[]之后,用";"分割。也可以换行写入,就不需要";"了
实例:
# 判断登录的用户是否为root #!/bin/bash # 把当前用户名赋值给变量test test=$(env | grep "USER" | cut ‐d "=" ‐f 2) if [ "$test"==root ];then echo "current user is root" fi # 判断分区使用率 #!/bin/bash test=$(df ‐h | grep sda5 | awk '{print $5}' | cut ‐d "%" ‐f 1) # 把分区使用率作为变量值赋予变量 test if [ ‐ge 90 ];then echo "文件满了" fi
2、双分支语句
if [ 条件判断式 ];then 条件成立时,执行的程序 else 条件不成立时,执行的另一个程序 fi
实例:
# 判断输入的是不是目录 #!/bin/bash read ‐t 30 ‐p "please input a dir :" dir if[ ‐d "$dir" ];then # 注意前后的空格 echo "输入的是目录" else echo "输入的不是目录" fi # 判断 apache 是否启动 #!/bin/bash test = $(ps aux | grep httpd | grep ‐v grep) # 截取httpd进程,并把结果赋予变量test if [ ‐n test ];then # 如果test不为空 echo "the apache is on running!" >> /~/running.log else /etc/rc.d/init.d/httpd start &> dev/null echo "the apache is restart!" >> /~/restart.log fi
3、多分支语句
if [ 条件判断式1 ] then 当条件判断式1成立时,执行程序1 elif [ 条件判断式2 ] then 当条件判断式2成立时,执行程序2 ...省略更多条件.... else 当所有条件都不成立,最后执行此程序 fi
#!/bin/bash # 从键盘输入获取数字赋值给变量age read age if (( $age <= 2 )); then echo "婴儿" elif (( $age >= 3 && $age <= 8 )); then echo "幼儿" elif (( $age >= 9 && $age <= 17 )); then echo "少年" elif (( $age >= 18 && $age <=25 )); then echo "成年" elif (( $age >= 26 && $age <= 40 )); then echo "青年" elif (( $age >= 41 && $age <= 60 )); then echo "中年" else echo "老年" fi
4、Shell分支 case语句
case 语句和 if...elif...else 语句一样都是多分支条件语句,不过和多分支 if 条件语句不同的是,case 语句只能判断 一种条件关系,而 if 语句可以判断多种条件关系。
case 变量名 in 值1) 如果变量的值等于值1则执行指令1 ;; 值2) 如果变量的值等于值2则执行指令2 ;; 值3) 如果变量的值等于值3则执行指令3 ;; *) 如果变量的值不等于以上列出的任何值则执行默认指令 esac
- case 语句比较适合变量值较少且为固定的数字或字符串集合情况(非不确定的内容,例如范围),如果变量的值是已知固定的start/stop/restart等元素,那么采用case语实现就比较适合
- case主要是写服务的启动脚本,一般情况下,传参不同且具有少量的字符串,其适用范围窄
- if就是取值判断、比较、应用比case更广。几乎所有的case语句都可以用if条件语句实现
- case语句就相当于多分支的if/elif/else语句,但case语句的优势是更规范,直观
案例1:判断输入内容
1.apple 2.pear 3.banana 4.cherry # 当用户输入对应的数字选择水果的时候,告诉他选择的水果是什么,并给水果单词加上一种颜色(随意),要求用 case语句实现。 [root@hostname ~]# cat fruit.sh #!/bin/bash ############################################################## ############################################################## cat <<EOF 1.apple 2.pear 3.banana 4.cherry EOF read ‐p "请输入您的选择:" num red="