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]#