shell条件测试语句

条件测试语句

条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成
测试过程
,实现评估布尔声明,以便用在条件性环境下进行执行

若真,则状态码变量 $? 返回0

若假,则状态码变量 $? 返回1

1. 条件测试语法说明:

  • test<测试表达式>,例:test $a -eq 0

  • [ <测试表达式> ],和test 等价,建议使用 [ ],例:[ $a -eq 0 ]

  • [[ <测试表达式> ]],相关于增强版的 [ ], 支持[]的用法,且支持正则表达式和通配符,例:[[ $a -eq 0 ]]

提示:

  • [] 需要注意:[ 后面和 ] 前面必须有空格

  • [[]] 中可以使用通配符进行模式匹配

  • &&、 || 、> 、<等操作符可以应用于 [[]] 中,但不能用于 [] 中(转义可以)

  • 对整数进行关系运算,也可以使用shell的算术运算符(())

[root@centos8 ~]#type [
[ is a shell builtin
[root@centos8 ~]#help [
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.
[root@centos8 ~]#help test
test: test [expr]
......
File operators:

      -a FILE        True if file exists.
      -b FILE        True if file is block special.
      -c FILE        True if file is character special.
      -d FILE        True if file is a directory.
      -e FILE        True if file exists.
      -f FILE        True if file exists and is a regular file.
      -g FILE        True if file is set-group-id.
      -h FILE        True if file is a symbolic link.
      -L FILE        True if file is a symbolic link.
      -k FILE        True if file has its `sticky' bit set.
      -p FILE        True if file is a named pipe.
      -r FILE        True if file is readable by you.
      -s FILE        True if file exists and is not empty.
      -S FILE        True if file is a socket.
      -t FD          True if FD is opened on a terminal.
      -u FILE        True if the file is set-user-id.
      -w FILE        True if the file is writable by you.
      -x FILE        True if the file is executable by you.
      -O FILE        True if the file is effectively owned by you.
      -G FILE        True if the file is effectively owned by your group.
      -N FILE        True if the file has been modified since it was last read.
......

1.1 test<测试表达式> help test

test -f file && echo true || echo false    # 如果file存在打印echo true,不存在打印echo false

# test命令非(!)的写法:
test ! -f file && echo true || echo false  # 如果file不存在打印echo true,存在打印echo false

1.2 [ <测试表达式> ]

[ -f file ] && echo 1 || echo 0

# []命令非(!)的写法:
[ ! -f file ] && echo 0 || echo 1

1.3 [[ <测试表达式> ]]

[[ -f file && -d folder ]] && echo 1 || echo 0     # 如果文件存在并且目录也存在,输出1,否则输出0
[ -f file ] && [  -d folder ] && echo 1 || echo 0  # 如果文件存在并且目录也存在,输出1,否则输出0
[ -f file -a -d folder ] && echo 1 || echo 0       # 如果文件存在并且目录也存在,输出1,否则输出0

# []命令非(!)的写法:
[[ ! -f file ]] && echo 0 || echo 1

示例:

dir=/server/scripts
file=s1
cd $dir || mkdir -p $dir   # 进入/server/scripts目录,如果不存在就创建/server/scripts
[ ! -f "$file" ] && touch $file || echo $file

判断的坑

字符串对比 if [ $str == "" ]; then

  • 坑1:如果 $str 为空字符串;脚本会报语法错,你等于写了如下这个脚本if [ == "" ];then

  • 坑2:如果 $str 是个带有空格的字符串 "cat dog",同样会报语法错误,因为 if [ cat dog == "" ]; then 显然不正确

  • 建议:字符串对比的时候,一定要加上双引号

    if [ $2"x" != "x" ];then
      times=$2
    fi
    

2. 变量测试

# 判断 NAME 变量是否定义 
[ -v NAME ]

# 判断 NAME 变量是否定义并且是名称引用,bash 4.4新特性 
[ -R NAME ]

示例

[root@centos8 ~]#unset var
[root@centos8 ~]#test -v var
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#var=song
[root@centos8 ~]#test -v var
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#VAR=
[root@centos8 ~]#test -v VAR
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#

# 注意 [ ] 需要空格,否则会报下面错误
[root@centos8 ~]#[-v VAR]
-bash: [-v: command not found
[root@centos8 ~]#[ -v VAR ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#

3. 文件测试操作符

3.1 存在性测试

header 1 header 2
[ -a FILE ] 如果 FILE 存在则为真。
[ -e FILE ] 如果 FILE 存在则为真,这里的文件可以是目录,要区别 f
[ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真。
[ -c FILE ] 如果 FILE 存在且是一个字特殊文件则为真。
[ -d FILE ] 如果 FILE 存在且是一个目录则为真。
[ -f FILE ] 如果 FILE 存在且是一个普通文件则为真。
[ -h FILE ] 如果 FILE 存在且是一个符号连接则为真。
[ -p FILE ] 如果 FILE 存在且是一个名字管道(F如果O)则为真。
[ -S FILE ] 如果 FILE 存在且是一个套接字则为真。

3.2 文件权限测试

header 1 header 2
[ -r FILE ] 如果 FILE 存在且是可读的则为真。
[ -w FILE ] 如果 FILE 存在且是可写的则为真。
[ -x FILE ] 如果 FILE 存在且是可执行的则为真。
[ -u FILE ] 如果 FILE 存在且设置了SUID (set user ID)则为真。
[ -g FILE ] 如果 FILE 存在且已经设置了SGID则为真。
[ -k FILE ] 如果 FILE 存在且已经设置了粘制位(sticky)则为真。

注意:最终结果由用户对文件的实际权限决定,而非文件属性决定

示例

[root@centos8 ~]#[ -w /etc/shadow ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -x /etc/shadow ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#touch test.txt
[root@centos8 ~]#[ -w test.txt ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#chattr +i test.txt
[root@centos8 ~]#lsattr test.txt
----i--------------- test.txt
[root@centos8 ~]#[ -w test.txt ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#chattr -i test.txt
[root@centos8 ~]#[ -w test.txt ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#

3.3 文件属性测试

header 1 header 2
[ -s FILE ] 如果 FILE 存在且大小不为0则为真。
[ -t FD ] 如果文件描述符 FD 打开且指向一个终端则为真。
[ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read则为真。
[ -O FILE ] 如果 FILE 存在且属有效用户ID则为真。
[ -G FILE ] 如果 FILE 存在且属有效用户组则为真。
[ -L FILE ] 如果 FILE 存在且是一个符号连接则为真。
[ FILE1 -nt FILE2 ] 若文件 FILE1 比文件 FILE2 新则真
[ FILE1 -ot FILE2 ] 若文件 FILE1 比文件 FILE2 旧则真
[ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的设备和节点号则为真,即,FILE1是否是FILE2的硬链接

示例

if [ $# -ne 3 ]; then
        echo "usage : sh $0 A|B Config Cur_Hour"
        exit 1
fi

TYPE=$1
# [ -z STRING ] “STRING” 的长度为零则为真。
if [ -z $TYPE ];then
        echo "TYPE parameter is empty."
        echo "usage : sh $0 A|B Config Cur_Hour"
        exit 1
fi

CONFIG=$2
# [ -f FILE ] 如果 FILE 存在且是一个普通文件则为真。
if [ ! -f $CONFIG ]; then
        echo "config parameter is empty."
        echo "usage : sh $0 A|B Config Cur_Hour"
        exit 1
fi

CURRENT_HOUR=$3
# [ -z STRING ] “STRING” 的长度为零则为真。
if [ -z $CURRENT_HOUR ]; then
        echo "CURRENT_HOUR parameter is empty."
        echo "usage : sh $0 A|B Config Cur_Hour"
        exit 1
fi

if [ $? -eq 0 -a -s ${tmp_file} ];then
   rsync -aP ${tmp_file} ${zabbix_file}
else 
   /opt/monitor/sendsms.sh "zabbix Connection to the platform database(machine) failed" "songwanbo"	
   exit 
fi

4. 字符串测试

test和 [ ]用法

test和 [ ]用法

-z STRING    # 字符串是否为空,没定义或空为真,不空为假, 
-n STRING    # 字符串是否不空(non-zero),不空为真,空为假
STRING       # 同上
   
STRING1 = STRING2             # 是否等于,注意 = 前后有空格 
STRING1 != STRING2            # 如果字符串不相等则为真
[ STRING1 < STRING2 ]         # 如果 “STRING1”字典排序(ascii码)在“STRING2”前面则返回为真。
[ STRING1 > STRING2 ]         # 如果 “STRING1”字典排序(ascii码)在“STRING2”后面则返回为真。

示例:判断当前用户是否为 root

[root@centos8 ~]#[ $(whoami) = root ];echo $?   # 不够严谨,因为显示 root 不一定就是管理员
0
[root@centos8 ~]#[ $(id -u) -eq 0 ];echo $?     # 使用 id=0 判断更为严谨
0
[root@centos8 ~]#

[[]] 用法

[[ expression ]] 用法

== 左侧字符串是否和右侧的PATTERN相同
注意:此表达式用于[[ ]]中,PATTERN为通配符

=~ 左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
注意: 此表达式用于[[ ]]中;扩展的正则表达式

建议:当使用正则表达式或通配符使用[[ ]],其它情况一般使用 [ ]

  • "=" 比较两个字符串是否相同,与==等价,如if[ "$a" = "$b" ] ,其中$a这样的变量最好用""括起来,因为如果中间有空格等就出错了,当然最好的方法是if[ "${a}" = "${b}" ]

  • "!=" 比较两个字符串是否相同,不同则为“是”

  • -z "字符串" 若长度为0则为真,-z可以理解为zero

  • -n "字符串" 若长度不为0则真,-n可以理解为no zero

  • "字符串1"="字符串2" 若字符串1等于字符串2则真,可以用“==”代替“=”

  • "字符串1"!="字符串2" 若字符串1不等于字符串2则真

[root@centos8 ~]#str=""
[root@centos8 ~]#set |grep str
str=
[root@centos8 ~]#unset str
[root@centos8 ~]#set |grep str
_=str
[root@centos8 ~]#str="";[ -z $str ];echo $str

[root@centos8 ~]#str="";[ -z $str ];echo $?
0
[root@centos8 ~]#


[ -n "$file" ] && echo 1 || echo 0    # 若长度不为0则真,因$file未定义长度,所以为假(0)

[ -z "$file" ] && echo 1 || echo 0    # 若长度为0则为真,因$file未定义长度,所以为真(1)

示例:使用 [[ ]] 判断文件后缀

[root@centos8 ~/script]#file=a.sh;[[ $file == *.sh ]] && echo true || echo false
true
[root@centos8 ~/script]#


# 通配符
[root@centos8 ~]#file=test.log
[root@centos8 ~]#[[ "$file" == *.log ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#file=test.txt
[root@centos8 ~]#[[ "$file" == *.log ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[[ "$file" != *.log ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#

# 正则表达式
[root@centos8 ~]#[[ "$FILE" =~ \.log$ ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#FILE=test.log
[root@centos8 ~]#[[ "$FILE" =~ \.log$ ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#

示例:判断合法的非负整数

[root@centos8 ~]#n=100
[root@centos8 ~]#[[ "$n" =~ ^[0-9]+$ ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#n=hello100
[root@centos8 ~]#[[ "$n" =~ ^[0-9]+$ ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#

示例: 判断合法IP

[root@centos8 ~]#IP=1.2.3.4
[root@centos8 ~]#[[ "$IP" =~  ^([0-9]{1,3}\.){3}[0-9]{1,3}$  ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#IP=1.2.3.4567
[root@centos8 ~]#[[ "$IP" =~  ^([0-9]{1,3}\.){3}[0-9]{1,3}$  ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#

cat check_ip.sh
IP=$1
[[ $IP =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]
{2}|2[0-4][0-9]|25[0-5])$ ]] && echo $IP is valid || echo $IP is invalid

示例:测试网络是否连通

[root@centos8 ~/script]#cat checkping.sh
#!/bin/bash
#
[ $# -ne 1 ] && { echo "Usage: $0 IP";exit 0; }
ping -c1 -W1 $1 &>/dev/null && echo "$1 is up" || { echo "$1 is down"; exit; }  # 如果&& 和 || 混合使用,&& 要在前,|| 放在后
echo "Scripts is finished"
[root@centos8 ~/script]#bash checkping.sh 172.18.0.11
172.18.0.11 is down
[root@centos8 ~/script]#bash checkping.sh 172.18.0.125
172.18.0.125 is down
[root@centos8 ~/script]#bash checkping.sh 172.18.0.100
172.18.0.100 is up
Scripts is finished
[root@centos8 ~/script]#
[root@centos8 ~/script]#cat checkping.sh
#!/bin/bash
#
#[ $# -ne 1 ] && { echo "Usage: $0 IP";exit 0; }
NET=172.18.0
for IP in {1..254}
do
	{
		ping -c1 -W1 $NET.$IP &>/dev/null && echo "$NET.$IP is up" \
		| tee -a host_list.log || echo "$NET.$IP is down"
	}&
done
wait
[root@centos8 ~/script]#

示例:在比较字符串时,建议变量放在""中

[root@centos8 ~]#NAME="I love linux"
[root@centos8 ~]#[ $NAME ]
-bash: [: love: binary operator expected
[root@centos8 ~]#[ "$NAME" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#

示例:[[ ]] 和通配符

# [[]]中如果不想使用通配符*,只想表达*本身,可以用" "引起来
[root@centos8 ~]#FILE="a*"
[root@centos8 ~]#[[ $FILE == a"*" ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#FILE="ab"
[root@centos8 ~]#[[ $FILE == a"*" ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#

# [[]]中如果不想使用通配符*,只想表达*本身,也可以使用转义符
[root@centos8 ~]#[[ $FILE == a\* ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#FILE="a\b"
[root@centos8 ~]#[[ $FILE == a\* ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#FILE="a*"
[root@centos8 ~]#[[ $FILE == a\* ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#

# 通配符?
[root@centos8 ~]#FILE=abc
[root@centos8 ~]#[[ $FILE == ??? ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#FILE=abcd
[root@centos8 ~]#[[ $FILE == ??? ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#

# 通配符
[root@centos8 ~]#NAME="linux1"
[root@centos8 ~]#[[ "$NAME" == linux* ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[[ "$NAME" == "linux*" ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#NAME="linux*"
[root@centos8 ~]#[[ "$NAME" == "linux*" ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#
# 结论:[[ == ]] == 右侧的 * 做为通配符,不要加“”,只想做为*, 需要加“” 或转义

示例:判断合理的考试成绩

[root@centos8 ~]#SCORE=101
[root@centos8 ~]#[[ $SCORE =~ 100|[0-9]{1,2} ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[[ $SCORE =~ ^(100|[0-9]{1,2})$ ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#SCORE=10
[root@centos8 ~]#[[ $SCORE =~ ^(100|[0-9]{1,2})$ ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#SCORE=abc
[root@centos8 ~]#[[ $SCORE =~ ^(100|[0-9]{1,2})$ ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#

5. 数值测试

在 [] 中使用的比较符 在 (()) 和 [[]] 中使用的比较符 说明
-eq == 相等(equal)
-ne != 不相等(no equal)
-gt > 大于(greater than)
-ge >= 大于等于(greater equal)
-lt < 小于(less than)
-le <= 小于等于(less equal)
  • "<" 符号意思是小于,if [[ "$a" < "$b" ]];if [ "$a" \< "$b" ],在 [] 中需要转义,因为shell也用 < 和 > 重定向

  • ">" 符号意思是大于,if [[ "$a" > "$b" ]];if [ "$a" \> "$b" ],在 [] 中需要转义,因为 shell 也用 < 和 > 重定向

  • 在 [[ ]] ,算数运算只能有 -eq, -ne, -lt, -le, -gt, or -ge

  • < 和 > 是字符串比较的,bash手册中没有说过可以做算术运算

-eq 等于
如:if [ "$a" -eq "$b" ]

-ne 不等于
如:if [ "$a" -ne "$b" ]

-gt 大于
如:if [ "$a" -gt "$b" ]

-ge 大于等于
如:if [ "$a" -ge "$b" ]

-lt 小于
如:if [ "$a" -lt "$b" ]

-le 小于等于
如:if [ "$a" -le "$b" ]

大于(需要双括号)
如:(("$a" > "$b"))

>= 大于等于(需要双括号)
如:(("$a" >= "$b"))

算数表达式比较

== 相等 
!= 不相等 
<=
>=
<
>

示例

[root@centos8 ~]#x=10;y=10;(( x == y ));echo $?
0
[root@centos8 ~]#x=10;y=20;(( x == y ));echo $?
1
[root@centos8 ~]#x=10;y=20;(( x != y ));echo $?
0
[root@centos8 ~]#x=10;y=10;(( x != y ));echo $?
1
[root@centos8 ~]#
[root@centos8 ~]#x=10;y=20;(( x > y ));echo $?
1
[root@centos8 ~]#x=10;y=20;(( x < y ));echo $?
0
[root@centos8 ~]#

示例1:

[@sjs_115_196 odin]# i="song song.jpg";if [ "$i" = "song song.jpg" ];then echo $i;fi 
song song.jpg
[@sjs_115_196 odin]# i="song song.jpg";if [[ "$i" == "song song.jpg" ]];then echo $i;fi
song song.jpg

6. 逻辑操作符

在 [] 中使用的比较符 在 (()) 和 [[]] 中使用的比较符 说明
-a && 与,两端都为真,则真
-o `
! ! 非,相反则为真

6.1 第一种方式

[ EXPRESSION1 -a EXPRESSION2 ]   # 并且,EXPRESSION1和EXPRESSION2都是真,结果才为真

[ EXPRESSION1 -o EXPRESSION2 ]   # 或者,EXPRESSION1和EXPRESSION2只要有一个真,结果就为真

[ ! EXPRESSION ]                 # 取反

说明: -a 和 -o 需要使用测试命令进行,[[ ]] 不支持

# 条件表达式的用法
[ -f "$file1" ] && echo 1 || echo 0                

# if条件语句的用法
if [ -f "file1" ];then 
    echo 1
else 
    echo 0
fi       
  • 以上两条语句的功能是等同的

  • 变量$file加了双引号,可以防止很多意外错误的发生

#!/bin/bash
cur_free=$(free -m |grep buffers\/|awk '{print $NF}')
msg="our system memory is:$cur_free"
if [ $cur_free -lt 100 ];then
    echo $msg|mail -s "$msg" 262410965@qq.com  (yum -y install sendmail )
fi

示例

[root@centos8 /data]#ll /data/sum.sh
-rw-r--r-- 1 root root 0 Apr  5 11:52 /data/sum.sh
[root@centos8 /data]#FILE="/data/sum.sh"
[root@centos8 /data]#[ -f $FILE -a -x $FILE ]
[root@centos8 /data]#echo $?
1
[root@centos8 /data]#chmod +x /data/sum.sh
[root@centos8 /data]#[ -f $FILE -a -x $FILE ]
[root@centos8 /data]#echo $?
0
[root@centos8 /data]#ll /data/sum.sh
-rwxr-xr-x 1 root root 0 Apr  5 11:52 /data/sum.sh
[root@centos8 /data]#
[root@centos8 /data]#chmod -x /data/sum.sh
[root@centos8 /data]#ll /data/sum.sh
-rw-r--r-- 1 root root 0 Apr  5 11:52 /data/sum.sh
[root@centos8 /data]#[ -f $FILE -o -x $FILE ]
[root@centos8 /data]#echo $?
0
[root@centos8 /data]#[ -x $FILE ]
[root@centos8 /data]#echo $?
1
[root@centos8 /data]#[ ! -x $FILE ]
[root@centos8 /data]#echo $?
0
[root@centos8 /data]#! [ -x $FILE ]
[root@centos8 /data]#echo $?
0
[root@centos8 /data]#

6.2 第二种方式

COMMAND1 && COMMAND2     # 并且,短路与,代表条件性的AND THEN 如果COMMAND1 成功,将执行COMMAND2,否则,将不执行COMMAND2

COMMAND1 || COMMAND2     # 或者,短路或,代表条件性的OR ELSE 如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2

! COMMAND                # 非,取反

示例:磁盘使用超过80%报警

[root@centos8 ~/script]#cat disk.sh
#!/bin/bash
#
warning=1
diskwarning=$(df -h|awk '!/Filesystem/{split($5,arr,"%");if(arr[1]>1){print $1 " is " arr[1] " waring "}}')

echo "${diskwarning}"| mail -s 'disk is warning' 262410965@qq.com
[root@centos8 ~/script]#
posted @ 2021-04-06 21:00  临江仙我亦是行人  阅读(74)  评论(0编辑  收藏  举报