三、条件测试
为了能够正确处理Shell程序运行过程中遇到的各种情况,Linux Shell提供了一组测试运算符。通过这些运算符,Shell程序能够判断某种或者几个条件是否成立。条件测试在各种流程控制语句,例如判断语句和循环语句中发挥了重要的作用,所以了解和掌握这些条件测试是非常重要的。
在shell程序中,用户使用测试语句来测试指定的条件表达式的条件的真或假。当指定的条件为真时,整个条件测试的返回值为0;反之,如果指定的条件为假,则条件测试语句的返回值为非0值。
3.1条件测试的基本语法
bash
格式1: test -选项 条件表达式
格式2: [ 条件表达式 ] # 注意:[]的左右要有空格
格式3: [[ 条件表达式 ]] # 注意:[[]]的左右要有空格
格式4: ((条件表达式))
!Note
条件测试的目标可以是文件、字符串、整数;
test,[]和[[]]语法适用于测试文件、字符串和整数;
(())语法只可以测试整数。
3.2文件测试表达式
| 常用的文件测试操作符 | 说明 |
|---|---|
| -a/-e 文件 | 文件是否存在 |
| -b 文件 | 文件是否存在,且为块文件,如果文件存在且是一个块文件,则结果为0 |
| -c 文件 | 文件是否存在且为字符文件,如果文件存在且是一个字符文件,则结果为0 |
| -L 文件 | 文件存在且为链接文件则为真 |
| -d 文件 | 文件存在且为目录则为真,即测试表达式成立 |
| -f 文件 | 文件存在且为普通文件则为真,即测试表达式成立 |
| -s 文件 | 文件存在且文件大小不为0则为真 |
| -u 文件 | 文件是否设置suid位,如果设置了suid,则结果为0 |
| -r 文件 | 文件存在且可读为真 |
| -w 文件 | 文件存在且可写为真 |
| -x 文件 | 文件存在且可执行则为真 |
| f1 -nt f2,nt为newer than | 文件f1比文件f2新则为真,根据文件的修改时间来计算 |
| f1 -ot f2,ot为older than | 文件f1比文件f2旧则为真,根据文件的修改时间来计算 |
bash
[root@server ~]# test -d /root && echo y || echo n
y
[root@server ~]# [ -d /root ] && echo y || echo n
y
[root@server ~]# [[ -d /root ]] && echo y || echo n
y
#如果文件存在,输出文件已经存在,如果不存在则创建
[root@server ~]# [ -e /root/file ] && echo "file alreay exists" || touch /root/file
#因为文件已经创建了,所以再次执行会提示已存在
[root@server ~]# [ -e /root/file ] && echo "file alreay exists" || touch /root/file
file alreay exists
**练习:**让用户输入一个文件名,并做如下判断:
(1)如果用户输入的文件名为空时显示:you must input a filename,并中断程序;
(2)如果用户输入的文件不存在时,显示the file do not exist,并中断程序;
(3)如果文件存在,判断该文件的文件类型和执行者对该文件所拥有的的权限。
说明:由于root在很多权限的限制上面都是无效的,所以使用root执行这个脚本时,常常会发现与ls -l的结果不相同。所以建议使用一般用户来执行这个脚本。
shell
[root@server ~]# mkdir /shell/chap03
[root@server ~]# vim /shell/chap03/test1.sh
read -p "input a filename:" filename
test -z $filename && echo "you must input a filename" && exit 0
test ! -e $filename && echo "the file $filename do not exist" && exit 0
test -f $filename && filetype="regulare file"
test -d $filename && filetype="directory"
test -r $filename && perm="readable"
test -w $filename && perm="$perm writable"
test -x $filename && perm="$perm executable"
echo "the $filename is a $filetype"
echo "and the permissons are: $perm"
[root@server ~]# bash /shell/chap03/test1.sh
input a filename:/root
the /root is a directory
and the permissons are: readable writable executable
3.3字符串测试表达式
| 常用字符串测试操作符 | 说明 |
|---|---|
| -n "字符串" | 若字符串的长度不为0,则为真,即测试表达式成立,n可以理解为no zero |
| -z "字符串" | 若字符串的长度为0,则为真,z可以理解为zero |
| "串1" = "串2" | 若字符串1等于字符串2,则为真,可使用==代替= |
| "串1" != "串2" | 若字符串1不等于字符串2,则为真 |
建议使用双引号将字符串或者变量引起来,不然可能出现错误的判断结果。
=和!=的判断时,左右两边字符串和符号间需要有空格。
bash
[root@server ~]# test -n "abc";echo $?
0
[root@server ~]# test -n "";echo $?
1
[root@server ~]# test -n " ";echo $?
0
[root@server ~]# [ -n " " ];echo $?
0
[root@server ~]# [[ -n " " ]];echo $?
0
[root@server ~]# test "abc" = "abcd" ;echo $?
1
[root@server ~]# test "abc" != "abcd" ;echo $?
0
[root@server ~]# [ "abc" != "abcd" ] ;echo $?
0
#如果测试的对象是变量,变量需要加引号
[root@server ~]# str1="abc"
[root@server ~]# str2="abcd"
[root@server ~]# test "$str1" = "$str2";echo $?
1
3.4整数测试表达式
| 在[]以及test中使用的比较符号 | 在(())和[[]]中使用的比较符号 | 说明 |
|---|---|---|
| -eq | ==或= | 相等,全拼为equal |
| -ne | != | 不相等,全拼为not equal |
| -gt | > | 大于,全拼为greater than |
| -ge | >= | 大于等于,全拼为greater equal |
| -lt | < | 小于,全拼为less than |
| -le | <= | 小于等于,全拼为less equal |
bash
[root@server ~]# test 5 -gt 3 && echo y || echo n
[root@server ~]# [ 5 -gt 3 ] && echo y || echo n
y
[root@server ~]# [[ 5 > 3 ]] && echo y || echo n
y
[root@server ~]# (( 5 > 3 )) && echo y || echo n
y
[[]]的特殊用法:
使用=~可以判断左侧是否包含右侧表达式中的字符。
bash[root@server ~]# n=123 [root@server ~]# [[ "$n" =~ ^[0-9]+$ ]] && echo y || echo n y [root@server ~]# n=123a [root@server ~]# [[ "$n" =~ ^[0-9]+$ ]] && echo y || echo n n
3.5逻辑操作符
| 在[]、test中使用的逻辑操作符 | 在[[]]和(())中使用的逻辑操作符 | 说明 |
|---|---|---|
| -a | && | and,与,两端都为真,则结果为真 |
| -o | || | or,或,两端有一个为真,则结果为真 |
| ! | ! | not,非,两端相反,则结果为真 |
bash
[root@server ~]# test -f /etc/passwd -a "abc" = "abcd" ;echo $?
1
[root@server ~]# ! test 3 -eq 3;echo $?
1
[root@server ~]# [ -f /etc/passwd -a "abc" = "abcd" ];echo $?
1
[root@server ~]# ! [ 3 -eq 3 ];echo $?
1
[root@server ~]# [[ -f /etc/passwd && "abc" = "abcd" ]];echo $?
1
[root@server ~]# ! [[ 3 -eq 3 ]];echo $?
1
[root@server ~]# (( 1 > 2 || 3 < 4));echo $?
0
[root@server ~]# ! (( 1 > 2 || 3 < 4));echo $?
1
3.6 案例
1、判断当前登录系统的用户数量,如果超过5个则输出"Too many"
bash
[root@server ~]# num=$(who | cut -d " " -f1 | sort -u | wc -l)
[root@server ~]# [ $num -gt 5 ] && echo "Too many" || echo "已登录账户数:$num"
已登录账户数:1
2、如果/var/log/messages文件行数大于30行,则显示提示信息
bash
[root@server ~]# line=$(cat /var/log/messages | wc -l)
[root@server ~]# [ "$line" -gt 30 ] && echo "好大一个文件" || echo "还能接受"
好大一个文件
3、查看ssh进程是否在运行:查看进程是否存在和查看是否监听,最后比较的数值不一样。
bash
[root@server ~]# num=$(ps -ef | grep ssh | wc -l)
[root@server ~]# [ "$num" -gt 1 ] && echo "ssh is running" || echo "ssh is not running"
ssh is running
[root@server ~]# num=$(ss -lntup | grep 22| wc -l)
[root@server ~]# [ "$num" -gt 0 ] && echo "ssh is running" || echo "ssh is not running"
ssh is running
4、编写脚本compute.sh,从键盘读入x,y,计算和值后输出
bash
[root@server ~]# vim /shell/chap03/compute.sh
#!/bin/bash
read -p "请输入x的值:" x
read -p "请输入y的值:" y
if [ -n "$x" -a -n "$y" ] # -n判断非空
then
if [[ "$x" =~ ^[0-9]+$ ]] && [[ "$y" =~ ^[0-9]+$ ]] # 判断是数字
then
echo $x+$y=$[x+y]
else
echo "请输入数字"
fi
else
echo "请输入有效内容"
fi
[root@server ~]# bash /shell/chap03/compute.sh
请输入x的值:3
请输入y的值:4
3+4=7