shell编程:条件测试与比较(六)
条件测试方法综述
test条件测试的简单语法及测试
范例6-1 测试文件(在test命令中使用-f选项:文件存在且为不同文件则表达式成立)
[root@adminset ~]# test -f file && echo true || echo false false [root@adminset ~]# touch file [root@adminset ~]# test -f file && echo true || echo false true
范例6-2 测试字符串(在test命令中使用-z选项(如果测试字符串的长度为0,则表达式成立)
[root@adminset ~]# test -z "luoahong" && ehco 1 || echo 0 0 [root@adminset ~]# char="luoahong" 0 [root@adminset ~]# test -z "$char" && echo 1 || echo 0 0 [root@adminset ~]# char="" [root@adminset ~]# test -z "$char" && echo 1 || echo 0 1
结论:test命令测试的功能很强大,但是和[] [[]]的功能有所重合,因此,在实际工作中选择一种适合自己的语法就好了,对于其他的语法,能读懂别人写的脚本就可以了
[](中括号)条件测试语法及示例
范例6-3 测试文件(利用[]加-f 选项 文件存在且为普通文件则表达式成立)
[root@adminset ~]# [ -f /tmp/luoahong.txt ] && echo 1 ||echo 0 0 [root@adminset ~]# touch /tmp/luoahong.txt [root@adminset ~]# [ -f /tmp/luoahong.txt ] && echo 1 ||echo 0 1 [root@adminset ~]# [ -f /tmp/luoahong.txt ] ||echo 0 [root@adminset ~]# [ -f /tmp/luoahong1.txt ] ||echo 0 0 [root@adminset ~]# [ -f /tmp/luoahong1.txt ] ||echo 0 0 [root@adminset ~]# touch /tmp/luoahong1.txt [root@adminset ~]# [ -f /tmp/luoahong1.txt ] ||echo 0 [root@adminset ~]# rm -f /tmp/luoahong1.txt [root@adminset ~]# [ -f /tmp/luoahong1.txt ] ||echo 0 0
提示:[]命令的选项和test的命令的选项是通用的,因此,使用[]时的参数选项可以通过man test命令获的帮助
文件测试表达式
范例6-5:文件属性条件表达式测试实践
[root@adminset ~]# ls -l luoahong -rw-r--r-- 1 root root 0 Jun 14 07:48 luoahong [root@adminset ~]# [ -r luoahong ] && echo 1 ||echo 0 1 #测试luoahong是否可读 [root@adminset ~]# [ -w luoahong ] && echo 1 ||echo 0 1 #测试luoahong是否可写 [root@adminset ~]# [ -x luoahong ] && echo 1 ||echo 0 0 #测试luoahong是否可执行 [root@adminset ~]# chmod 001 luoahong [root@adminset ~]# ls -l luoahong ---------x 1 root root 0 Jun 14 07:48 luoahong #修改后的结果 [root@adminset ~]# [ -w luoahong ] && echo 1 ||echo 0 1 #用户权限位明明没有w,为什么还是返回1呢? [root@adminset ~]# echo 'echo test' >oldboy #因为确实可以写啊,这是root用户比较特殊的地方 [root@adminset ~]# [ -r luoahong ] && echo 1 ||echo 0 1 #用户权限位明明没有r,为什么还是返回1呢? [root@adminset ~]# echo 'echo test' >luoahong [root@adminset ~]#cat luoahong echo test #因为确实可以读啊,这是root用户比较特殊的地方。 [root@adminset ~]# [ -x luoahong ] && echo 1 ||echo 0 1 [root@adminset ~]# ./luoahong [root@adminset ~]# ./luoahong test #可执行
提示:测试文件的读、写、执行等属性,不光是根据文件属性rwx的表示来判断,
还要看当前执行的用户是否真的可以按照对应的权限操作该文件
测试shell变量示例
root@adminset ~]# file1=/etc/services;file2=/etc/rc.local [root@adminset ~]# echo $file1 $file2 /etc/services /etc/rc.local
范例:对单个文件变量进行测试
[root@adminset ~]# [ -f "$file1" ] && echo 1 || echo 0 1 [root@adminset ~]# [ -d "$file1" ] && echo 1 || echo 0 0 [root@adminset ~]# [ -s "$file1" ] && echo 1 || echo 0 1 [root@adminset ~]# [ -e "$file1" ] && echo 1 || echo 0 1 [root@adminset ~]# [root@adminset ~]#
范例:对单个目录或文件进行测试
[root@adminset ~]# [ -e /etc ] && echo 1 || echo 0 1 [root@adminset ~]# [ -w /etc/serbices ] && echo 1 || echo 0 0 [root@adminset ~]# su - luoahong [luoahong@adminset ~]$ [ -w /etc/servies ] && echo 1 || echo 0 0 #文件不可写,所以返回0
范例:测试变量的特殊写法及问题
用测试变量时,如果被测试的变量不加双引号,那么测试结果可能会不时正确的示例如下:
[luoahong@adminset ~]$ echo $tyx #这是一个不存在的变量,如果读者已经定义、则可以执行unset取消 [luoahong@adminset ~]$ [ -f $tyx ] && echo 1 || echo 0 1 #命名$tyx变量不存在内容还返回1,逻辑就不对了 [luoahong@adminset ~]$ [ -f "$tyx" ] && echo 1 || echo 0 0 #加了双引号就返回0,逻辑就对了
如果是文件实体路径,那么加引号与不加引号的结果时一样的:
[luoahong@adminset ~]$ [ -f "/etc/services" ] && echo 1 || echo 0 1 [luoahong@adminset ~]$ [ -f /etc/services ] && echo 1 || echo 0 1
范例: 在生产环境下,系统NFS启动脚本的条件测试
more /etc/init.d/nfs # Source networking configuration. [ -f /etc/sysconfig/network ] && . /etc/sysconfig/network # Check for and source configuration file otherwise set defaults [ -f /etc/sysconfig/nfs ] && . /etc/sysconfig/nfs # Remote quota server [ -z "$RQUOTAD" ] && RQUOTAD=`type -path rpc.rquotad`
特别提示:系统脚本时我们学习编程的第一标杆,新手要多参考脚本来学习,虽然有些脚本也不是特别规范
范例:实现系统bind启动脚本named
[luoahong@adminset ~]$ [ -r /etc/sysyconfig/network ] && ./etc/sysconfig/network #若文件存在且可读,则加载/etc/sysconfig/network [luoahong@adminset ~]$ [ -x /usr/sbin/$named ] || exit 5
范例:写出简单高效的测试文件
在做测试判断时,不一定非要按照"前面的操作成功了如何,否则如何"的方法来进行。直接做部分判断,有时看起来更简洁
[luoahong@adminset ~]$ [ -x luoahong ] && echo 1 #如果luoahong可执行,则输出1;如果不可执行,则不做任何输出 [luoahong@adminset ~]$ [ -f /etc ] && echo 1 [luoahong@adminset ~]$ [ -f /etc ] && echo 0 #如果l/etc 是文件这一点不成立,则输出0,如果成立则不做任何输出
范例:实现系统脚本/etc/init.d/nfs
[luoahong@adminset ~]$ sed -n '44,50p' /etc/init.d/nfs # Check that networking is up. [ "${NETWORKING}" != "yes" ] && exit 6 #如果${NETWORKING}的变量内容不等于yes,则退出 [ -x /usr/sbin/rpc.nfsd ] || exit 5 #如果/usr/sbin/rpc.nfsd的脚本不可执行,则以返回值5退出脚本。如果可执行,则不做任何输出 [ -x /usr/sbin/rpc.mountd ] || exit 5 [ -x /usr/sbin/exportfs ] || exit 5
特殊表达式测试案例
范例:当条件不成立是,执行大括号里的多条命令,这里要使用逻辑操作符||
[root@adminset 06]# sh 6_15.sh 1 2 3 [root@adminset 06]# cat 6_15.sh [ -f /etc ] || { echo 1 echo 2 echo 3 } [root@adminset 06]# sh 6_15.sh 1 2 3
如果上述脚本写在一行里面,那么里面的每个命令都需要用分号结尾,示例如下所示:
[root@adminset 06]# [ -f /etc/services ] && { echo "I am luoahong"; echo "I am linuxer"; } I am luoahong I am linuxer
提示:本例的两种用法都很简洁,但是不如if条件容易理解,因此请读者根据自身情况选择使用,更多帮助请man test查询
字符串测试表达式
字符串测试操作符
范例:字符串条件表达式测试实践
[root@adminset 06]# [ -n "abc" ] && echo 1 || echo 0 1 [root@adminset 06]# test -n "" && echo 1 || echo 0 0 [root@adminset 06]# var="luoahong" [root@adminset 06]# [ -n "$var" ] && echo 1 || echo 0 1 [root@adminset 06]# [ -n $var ] && echo 1 || echo 0 1 [root@adminset 06]# var="luoahong1" [root@adminset 06]# [ -z $var ] && echo 1 || echo 0 0 [root@adminset 06]# [ "abc" = "abd" ] && echo 1 || echo 0 0 [root@adminset 06]# [ "$var" = "luoahong1" ] && echo 1 || echo 0 1 [root@adminset 06]# [ "$var" == "luoahong1" ] && echo 1 || echo 0 1 [root@adminset 06]# [ "$var" != "luoahong1" ] && echo 1 || echo 0 0
字符串测试生产案例
范例:有关双引号和等号两端空格的生产系统标准
[root@adminset 06]# sed -n '30,31p' /etc/init.d/network #check that networking is up [ "${NETWORKING}" = "no" ] && exit 6 #字符串变量和字符串都加了双引号,比较符号"="两端也都有空格
范例:系统脚本/etc/init.d/nfs字符串测试的应用示例
[root@adminset 06]# sed -n '65,80p' /etc/init.d/nfs [ -z "$MOUNTD_NFS_V2" ] && MOUNTD_NFS_V2=default #-z的应用,如果变量MOUNTD_NFS_V2的长度为0则赋值default [ -z "$MOUNTD_NFS_V3" ] && MOUNTD_NFS_V3=default #-z的应用,如果变量MOUNTD_NFS_V3的长度为0则赋值default # Number of servers to be started by default [ -z "$RPCNFSDCOUNT" ] && RPCNFSDCOUNT=8 # Start daemons. [ -x /usr/sbin/rpc.svcgssd ] && /sbin/service rpcsvcgssd start # Set the ports lockd should listen on if [ -n "$LOCKD_TCPPORT" -o -n "$LOCKD_UDPPORT" ]; then #-n的应用 [ -x /sbin/modprobe ] && /sbin/modprobe lockd $LOCKDARG [ -n "$LOCKD_TCPPORT" ] && \ /sbin/sysctl -w fs.nfs.nlm_tcpport=$LOCKD_TCPPORT >/dev/null 2>&1 [ -n "$LOCKD_UDPPORT" ] && \ /sbin/sysctl -w fs.nfs.nlm_udpport=$LOCKD_UDPPORT >/dev/null 2>&1 fi
整数变量测试示例
范例:通过[]实现整数条件测试
[root@adminset 06]# a1=98;a2=99 [root@adminset 06]# [ $a1 -eq $a2 ] && echo 1 ||echo 0 0 [root@adminset 06]# [ $a1 -gt $a2 ] && echo 1 ||echo 0 0 [root@adminset 06]# [ $a1 -lt $a2 ] && echo 1 ||echo 0 1
范例:利用[[]]和(())实现直接通过常规数学运算符进行比较
[root@adminset 06]# [[ $a1 > $a2 ]] && echo 1 ||echo 0 0 [root@adminset 06]# [[ $a1 < $a2 ]] && echo 1 ||echo 0 1 [root@adminset 06]# (($a1>=$a2)) && echo 1|| echo 0 0 [root@adminset 06]# (($a1<=$a2)) && echo 1|| echo 0 1
范例:系统脚本中使用整数比较的案例
[root@adminset ~]#grep -w "\-eq" /etc/init.d/nfs [ $RETVAL -eq 0 ] && RETVAL=$rval #过滤出相等(-eq)的例子 [ $RETVAL -eq 0 ] && RETVAL=$rval #使用[],且两边都要有一个空格 [ $RETVAL -eq 0 ] && RETVAL=$rval #使用"-eq" 的比较操作符的写法 [ $RETVAL -eq 0 ] && RETVAL=$rval [ $RETVAL -eq 0 ] && RETVAL=$rval [root@adminset ~]#grep -w "\-gt" /etc/init.d/nfs #过滤出大于(-gt)的例子 if [ $cnt -gt 0 ]; then
逻辑操作符实践示例
范例:[]里的逻辑操作配合文件测试表达式使用的示例
[root@adminset 06]# f1=/etc/rc.local;f2=/etc/services [root@adminset 06]# echo -ne "$f1 $f2\n" /etc/rc.local /etc/services [root@adminset 06]# [ -f "$f1" -a -f "$f2" ] && echo 1 || echo 0 1 [root@adminset 06]# [ -f "$f1" -o -f "$f222" ] && echo 1 || echo 0 1 [root@adminset 06]# [ -f "$f111" -o -f "$f222" ] && echo 1 || echo 0 0 [root@adminset 06]# [ -f "$f1" && -f "$f2" ] && echo 1 || echo 0 -bash: [: missing `]' 0 #这是错误的语法,[]中不能用&&|| [root@adminset 06]# [ -f "$f1" ] && [ -f "$f2" ] && echo 1 || echo 0 1 #如果在[]中使用&&,则这样用
范例:[[]]里逻辑操作符配合字符串的条件表达式的测试示例
[root@adminset 06]# a="luoahong";b="tyx" [root@adminset 06]# echo -ne "$a $b\n" luoahong tyx [root@adminset 06]# [[ ! -n " $a" && "$a" = "$b"]] && echo 1 || echo 0 -bash: conditional binary operator expected -bash: syntax error near `1' [root@adminset 06]# [[ ! -n "$a" && "$a" = "$b"]] && echo 1 || echo 0 -bash: conditional binary operator expected -bash: syntax error near `1' [root@adminset 06]# [[ ! -n "$a" && "$a" = "$b" ]] && echo 1 || echo 0 0 [root@adminset 06]# [[ -z "$a" || "$a" != "$b" ]] && echo 1 || echo 0 1 [root@adminset 06]# [root@adminset 06]# [[ -z "$a" -o "$a" != "$b" ]] && echo 1 || echo 0 -bash: syntax error in conditional expression -bash: syntax error near `-o'
范例:(())里逻辑操作符符合整数的条件表达式测试示例
[root@adminset 06]# m=21;n=38 [root@adminset 06]# ((m>20&&n>30)) && echo 1 || echo 0 1 [root@adminset 06]# ((m>20||n>30)) && echo 1 || echo 0 1 [root@adminset 06]# ((m<20||n<30)) && echo 1 || echo 0 0 [root@adminset 06]# ((m<20 -a n<30)) && echo 1 || echo 0 -bash: ((: m<20 -a n<30: syntax error in expression (error token is "n<30") 0 #内部用-a或-o也会报语法错误
范例:使用多个[]号,并通过与或非进行混合测试
[root@adminset 06]# m=21;n=38 [root@adminset 06]# [ $m =gt 20 -a $n -lt 30 ] && echo 1 || echo 0 -bash: [: too many arguments 0 [root@adminset 06]# [ $m gt 20 -a $n -lt 30 ] && echo 1 || echo 0 -bash: [: too many arguments 0 [root@adminset 06]# [ $m -gt 20 -a $n -lt 30 ] && echo 1 || echo 0 0 [root@adminset 06]# [ $m -gt 20 ] || [ $n -lt 30 ] echo 1 || echo 0 [root@adminset 06]# [ $m -gt 20 ] || [ $n -lt 30 ] && echo 1 || echo 0 1 #多个[]号之间用&&或||链接
范例:NFS系统启动脚本中有关[]与或非判断的使用案例
[root@adminset~]#egrep -wn "\-a|\-o" /etc/init.d/nfs 75: if [ -n "$LOCKD_TCPPORT" -o -n "$LOCKD_UDPPORT" ]; then 87: [ "$NFSD_MODULE" != "noload" -a -x /sbin/modprobe ] && { 102: if [ -n "$RQUOTAD" -a "$RQUOTAD" != "no" ]; then 170: if [ -n "$RQUOTAD" -a "$RQUOTAD" != "no" ]; then 209: if [ -n "$RQUOTAD" -a "$RQUOTAD" != "no" ]; then 229: if [ $MOUNTD = 1 -o $NFSD = 1 ] ; then
范例:系统启动脚本中有关[[]]的用法和与或非的使用案例
在操作系统中,[[]]的用法不是很多,并且大多数情况都用于通配符匹配的场景,这里不的不通过大海捞针的
方法(遍历/etc/init.d/下的所有脚本)来帮助大家查找[[]]的用法:
[root@69 ~]# for n in `ls /etc/init.d/*`;do egrep -wn "\[\[ " $n&&echo $n;done 119: if [[ "$dst" == /dev/mapper* ]] \ /etc/init.d/halt 68: if [[ $? = 0 ]]; then /etc/init.d/httpd 641: if [[ -n "$_target" ]]; then 656: if [[ "$_rmnt" == "$_mnt" ]] || ! is_dump_target_configured; then /etc/init.d/kdump 50: if [[ $route == *" via "* ]] ; then 75: if ! [[ "$SYSLOGADDR" =~ $IPv4_regex ]] && ! [[ "$SYSLOGADDR" =~ $IPv6_regex ]];then 80: if [[ $? -eq 2 ]]; then 84: if [[ $? -ne 0 ]]; then /etc/init.d/netconsole 167: if [[ "$rootfs" == nfs* || "$rootopts" =~ _r?netdev ]] ; then /etc/init.d/network
提示:可见[]中使用-a或-o更常见,[[]]中使用&&或||不常见,使用&&或||链接两个[]的多表达式判断也不常见
作者:罗阿红
出处:http://www.cnblogs.com/luoahong/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。