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更常见,[[]]中使用&&或||不常见,使用&&或||链接两个[]的多表达式判断也不常见

猜你喜欢

转载自www.cnblogs.com/luoahong/p/9215074.html