前言
写脚本时,为了让脚本更接近人类思考问题的方式,可以对各种情况进行判断。例如,经常需要判断某些条件是否成立,如果条件成立该如何处理,如果条件不成立又该如何处理,这些都可以通过Shell脚本的if语句结合各种条件判断来实现。
一 智能化脚本的基础之测试
在Shell中可以使用多种方式进行条件判断,如[[表达式]]、[表达式]或者test表达式。使用条件表达式可以测试文件属性,进行字符或数字的比较。需要注意的是,不管使用哪种方式进行条件判断,系统默认都不会有任何输出结果,可以通过echo $?命令,查看上一条命令的退出状态码,或者使用&&和||操作符结合其他命令进行结果的输出操作。
注意
表达式两边必须有空格,否则程序会出错。使用[[]]和test进行排序比较时,使用的比较符号不同。在test或[]中不能直接使用<或>符号进行排序比较。
如果需要在一行代码中输入多条命令,在Shell中可以使用;(分号)、&&(与)、||(或)这三个符号将多个命令分隔。其中;(分号)是按顺序执行命令,分号前后的命令可以没有任何逻辑关系。例如,输入“A命令;B命令”,系统会先执行A命令,不管A命令执行结果如何,都会执行B命令。整个命令的退出码以最后一条命令为准,B命令如果执行成功则退出码为0, B命令如果执行失败则退出码为非0。而使用&&(与)符号分隔多条命令时,仅当前一条命令执行成功后,才会执行&&后面的命令。例如,输入“A命令&&B命令”,系统会先执行A命令,如果A命令执行成功则执行B命令,如果A命令执行失败则不执行B命令。而整行命令的退出码取决于两条命令是否同时执行成功,如果A命令执行成功并且B命令执行也成功,则整行命令的退出码为0,而A命令或B命令中的任何一条命令执行失败,则整行命令的退出码为非0。如果使用||(或)符号分隔多条命令,仅当前一条命令不执行或执行失败后才执行后一条命令。例如,输入“A命令||B命令”,因为A命令是命令行的第一条命令,所以一定会执行,如果A命令执行成功了就不再执行B命令,如果A命令执行失败,则执行B命令, 所以一定会执行,如果A命令执行成功了就不再执行B命令,如果A命令执行失败,则执行B命令,A命令和B命令为二选一的关系。A命令或B命令中有任何一条命令的退出码为0,则整行命令的退出码就是0,否则返回非0。
二 实例验证
||(或符号)和&&验证:目录中没有hehe文件,所以ls hehe执行时,为假,不执行&& cat hehe,执行||后面的输出
csdn@ubuntu:~$ [ $(ls hehe) ] && cat hehe || (echo $?;echo "no file hehe";)
ls: 无法访问'hehe': 没有那个文件或目录
1
no file hehe
csdn@ubuntu:~$
有main.c文件,所以,判断main.c时,执行了&&后面的语句cat main.c。因为||前面的值已经为真,所以不执行||后面的语句。
csdn@ubuntu:~$ [ $(ls main.c) ] && (echo $?;cat main.c) || echo "no file main.c"
0
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
csdn@ubuntu:~$
三 字符串的判断与比较
下面的表达式使用test或[]测试的效果是一样,表达式中可以使用变量。使用$?查看上一条命令的退出码,0代表正确(true),非0代表错误(false)。
csdn@ubuntu:~$ test a == a;echo $?
0
csdn@ubuntu:~$ [ a == a ];echo $?
0
csdn@ubuntu:~$ test a == b;echo $?
1
csdn@ubuntu:~$ [ a == b ];echo $?
1
csdn@ubuntu:~$
下面的测试,因为当前用户是csdn,测试结果为假,所以跳过echo Y命令,执行echo N,结果屏幕仅显示N。
csdn@ubuntu:~$ [ $USER == root ] && echo Y || echo N
N
csdn@ubuntu:~$
切换用户到root,切换用户后,当前用户变成root,测试结果为真,所以会执行echo Y命令,而当echo Y命令执行并成功后,则不再执行echo N,结果屏幕仅显示Y。
csdn@ubuntu:~$ su
密码:
root@ubuntu:/home/csdn# [ $USER == root ] && echo Y || echo N
Y
root@ubuntu:/home/csdn#
在表达式中使用-z可以测试一个字符串是否为空,下面测试一个未定义的变量TEST,如果变量值为空则屏幕显示Y,否则显示N。 定义变量TEST后,输出N。使用unset释放变量后,输出值变为Y。
root@ubuntu:/home/csdn# [ -z $TEST ] && echo Y || echo N
Y
root@ubuntu:/home/csdn# TEST=123456
root@ubuntu:/home/csdn# [ -z $TEST ] && echo Y || echo N
N
root@ubuntu:/home/csdn# unset TEST
root@ubuntu:/home/csdn# [ -z $TEST ] && echo Y || echo N
Y
root@ubuntu:/home/csdn#
在Shell中进行条件测试时一定要注意空格问题。使用[]测试时,左方括号右边和右方括号左边都必须有空格。而且测试的比较符号两边也必须都有空格。
我们还可以使用-n测试一个字符串是否非空(变量值不为空)。但是在实际应用时最好将测试对象使用双引号引起来。
root@ubuntu:/home/csdn# TEST=123456
root@ubuntu:/home/csdn# [ -n $TEST ] && echo Y || echo N
Y
root@ubuntu:/home/csdn#
这样看起来没什么问题。但是,当测试一个未定义的变量时就会出故障。下面测试一个未定义的变量hello是否非空。为什么hello的度量值明明为空,但测试却说该变量值不为空呢?
root@ubuntu:/home/csdn# [ -n $hello ] && echo Y || echo N
Y
root@ubuntu:/home/csdn# echo $hello
root@ubuntu:/home/csdn#
因为,当$hello为空时,等同于执行了下面的第一条命令,是在测试一个空格是否为空值。而计算机理解空格也是有值的,并非没有值(空值),所以这样的测试结果总为真;但程序的逻辑其实已经出错了。为了防止类似这种错误,可以将变量使用双引号(单引号会屏蔽特殊字符,会将$变成一个普通字符,所以这里不能使用单引号)引起来。
root@ubuntu:/home/csdn# [ -n ] && echo Y || echo N
Y
root@ubuntu:/home/csdn# [ -n "$hello" ] && echo Y || echo N
N
root@ubuntu:/home/csdn#
四 整数的判断与比较
比较两个数字可能的结果有等于、不等于、大于、大于或等于、小于、小于或等于这么几种情况,在Shell脚本中支持对整数的比较判断,可以使用下表所示的符号进行比较运算。
root@ubuntu:/home/csdn# test 3 -eq 3 && echo Y || echo N
Y
root@ubuntu:/home/csdn# test 3 -ne 3 && echo Y || echo N
N
root@ubuntu:/home/csdn# test 3 -gt 3 && echo Y || echo N
N
root@ubuntu:/home/csdn# test 3 -ge 3 && echo Y || echo N
Y
root@ubuntu:/home/csdn# test 3 -lt 3 && echo Y || echo N
N
root@ubuntu:/home/csdn# test 3 -le 3 && echo Y || echo N
Y
root@ubuntu:/home/csdn#
综合案例
案例1:判断系统可用内存是否大于400MB
下面这个案例使用grep命令结合正则表达式,从meminfo文件中过滤当前系统剩余可用的内存容量,剩余容量以KiB为单位,最后测试剩余可用容量是否小于或等于400MiB。
root@host:~# cat /proc/meminfo | grep Available
MemAvailable: 432424 kB
root@host:~#
grep命令使用-o选项可以仅显示匹配内容,而不显示全行所有内容。
root@host:~# cat /proc/meminfo | grep Available | egrep -o "[0-9]+"
432348
root@host:~#
或者grep -E
root@host:~# cat /proc/meminfo | grep Available | grep -Eo "[0-9]+"
432408
root@host:~#
root@host:~# mem_free=$(grep Available /proc/meminfo | grep -Eo [0-9]+);echo $mem_free
432400
root@host:~#
判断小于400MB,输出N
root@host:~# [ $mem_free -le 409600 ] &&echo Y || echo N
N
root@host:~#
判断大于 400BM,输出Y
root@host:~# [ $mem_free -gt 409600 ] &&echo Y || echo N
Y
root@host:~#
案例2:判断进程数量
接下来使用ps命令,查看系统中所有启动的进程列表信息,结合wc命令还可以统计当前系统中已经启动的进程数量。这样,就可以判断是否启动了超过60个进程。
root@host:~# ps aux | wc -l
57
root@host:~# proc_num=$(ps aux | wc -l);echo $proc_num
58
root@host:~# [ $proc_num -gt 60 ] && echo Y || echo N
N
root@host:~#
案例3:判断账户数量
使用wc命令统计/etc/passwd文件的行数(有多少行就表示系统中有多少个账户),判断当前系统账户数量是否大于或等于30个。
root@host:~# cat /etc/passwd | wc -l
9
root@host:~# user_num=$(cat /etc/passwd | wc -l);[ $user_num -ge 30 ] && echo Y || echo N
N
root@host:~#