1. if-test
test是shell内置命令,用来检测某个条件是否成立。test通常和if语句一起使用,并且大部分if语句都依赖test。
test命令有很多选项,可以进行数值、字符串和文件三个方面的检测。
shell test 命令的用法为:test expression
当test判断expression成立时,退出状态为0,否则为非零值。
test命令也可以简写为[],他的用法为:[ expression ]
,注意[]和expression之间的空格,这两个空格时必须的,否则会导致语法错误。[]的写法更加简洁,比test使用频率高。
test命令可以判断3类条件:数值比较,字符串比较,文件比较。
2. test的数值比较
test命令的数值比较功能
比较 | 描述 |
---|---|
n1 -eq n2 | 检查n1是否与n2相等 |
n1 -ge n2 | 检查n1是否大于或等于n2 |
n1 -gt n2 | 检查n1是否大于n2 |
n1 -le n2 | 检查n1是否小于或等于n2 |
n1 -lt n2 | 检查n1是否小于n2 |
n1 -ne n2 | 检查n1是否不等于n2 |
#!/bin/bash
# 数值条件测试可以用在数字和变量上
read val
read val1
if [ $val -eq $val1 ]
then
echo "The test value $val is equal $val1"
elif [ $val -gt $val1 ]
then
echo "The test value $val is greater than $val1"
else
echo "The test value $val is lower than $val1"
fi
结果:
12
33
The test value 12 is lower than 33
33
33
The test value 33 is equal 33
注意:不能在test中使用符点值
3. test的字符串比较
比较 | 描述 |
---|---|
str1 = str2 | 检查str1是否和str2相同 |
str1 != str2 | 检查str1是否和str2不同 |
str1 < str2 | 检查str1是否比str2小 |
str1 > str2 | 检查str1是否比str2大 |
-n str1 | 检查str1的长度是否非0 |
-z str1 | 检查str1的长度是否为0 |
$USER的用法:
[kiosk@foundation60 ~]$ echo $USER
kiosk
#!/bin/bash
# 字符串的相等性
# 比较字符串相等性的时候,test的比较会将所有的标点和大写也考虑在内
luser=root
if [ $USER=$luser ]
then
echo "登录成功"
else
echo "登录失败"
fi
结果:
登录成功
# 大于小与符号必须转义
# 否则shell会把他们当作重定向符号,从而把字符串当作文件名
val1=zjy
val2=ljl
if [ $val1 \> $val2 ];then
echo "$val1 is greater than $val2"
else
echo "$val1 is less than $val2"
fi
结果:
zjy is greater than ljl
==注意:==字符串的比较遵循字典顺序,规则如下:如果第一个字符串是第二个字符串的前缀,那么第一个小,比如a小于about。从字符串的开头比较,按照字母顺序,a比b小,比如about小于ball。如果第一个字符相同,在比较第二个,比如about小于above。总之,如果你查字典,字典排在前面的单词比后面的单词小。
#!/bin/bash
# 注意:没有被定义的值也会有输出结果
val1=zjy
val2=''
if [ -n $val1 ];then
echo "$val1 is not empty"
else
echo "$val1 is empty "
fi
if [ -z $val2 ];then
echo "'$val2' is empty"
else
echo "'$val2' is not empty "
fi
if [ -z $val3 ];then
echo "'$val3' is empty"
else
echo "'$val3' is not empty "
fi
结果:
zjy is not empty
‘’ is empty
‘’ is empty
4. 文件比较
比较 | 描述 |
---|---|
-d file | 检查file是否存在并是一个目录 |
-e file | 检查file是否存在 |
-f file | 检查file是否存在并是一个文件 |
-r file | 检查file是否存在并可读 |
-s file | 检查file是否存在并非空 |
-w file | 检查file是否存在并可写 |
-x file | 检查file是否存在并可执行 |
-O file | 检查file1是否存在并属于当前用户所有 |
-G file | 检查file是否存在并且默认组与当前用户相同\ |
file1 -nt file2 | 检查file1是否比file2新 |
file1 -ot file2 | 检查file1是否比file2旧 |
#!/bin/bash
if [ -d $HOME ];then
echo "your HOME directory exits"
cd $HOME
ls -a
else
echo "There is a problem with your HOME diretory"
fi
结果:
your HOME directory exits
. .bashrc Downloads .mozilla .ssh
… .cache .esd_auth Music .tcshrc
anaconda-ks.cfg .config .gnome2 Pictures Templates
.bash_history .cshrc .gnome2_private Public Videos
.bash_logout Desktop .ICEauthority redhat_iso7.3 .viminfo
.bash_profile Documents .local shell
#!/bin/bash
if [ -e $HOME ]
then
echo "ok on the directory.now to check the file"
if [ -e $HOME/testing ]
then
echo "appending date to exiting file"
date >> $HOME/testing # 表示追加正确输出
else
echo "creating new file"
date > $HOME/testing # 表示重定向正确输出
fi
else
echo "sorry,you do not have a HOME directory"
fi
结果:
ok on the directory.now to check the file
creating new file
#!/bin/bash
if [ -e $HOME ];then
echo "the object exists.is it a file?"
if [ -f $HOME ];then
echo "yes,it is a file."
else
echo "no,it is not a file."
if [ -f $HOME/.bash_history ]
then
echo "but this is a file."
fi
fi
else
echo "sorry,the object does not exist."
fi
结果:
the object exists.is it a file?
no,it is not a file.
but this is a file.
#!/bin/bash
file=/etc/shadow
if [ -f $file ];then
if [ -r $file ];then
tail $file
else
echo "sorry,i am unable to read the $file file"
fi
else
echo "sorry,the file $file does not exist."
fi
结果:
saslauth:!!:16442::::::
ntp:!!:16442::::::
rtkit:!!:16442::::::
radvd:!!:16442::::::
pulse:!!:16442::::::
gdm:!!:16442::::::
gnome-initial-setup:!!:16442::::::
tcpdump:!!:16442::::::
apache:!!:18301::::::
dhcpd:!!:18301::::::
#!/bin/bash
file=stest
touch $file
if [ -s $file ];then
echo "the $file exists and has data in it"
else
echo "the $file exists and is empty"
fi
结果:
the stest exists and is empty
the stest exists and has data in it
#!/bin/bash
logfile=testroot
touch $logfile
now=`date +%Y%d-%H%M`
if [ -w $logfile ];then
echo "the program ran at:$now" > $logfile
echo "the first attempt succeeed"
else
echo "the first attempt failed"
fi
chmod u+w $logfile
if [ -w $logfile ];then
echo "the program ran at:$now" > $logfile
echo "the second attempt succeeed"
else
echo "the second attempt failed"
fi
结果:
testroot
the program ran at:202012-0932
#!/bin/bash
if [ -x test05.sh ];then
echo "you can run the scrip"
./test05.sh
else
echo "sorry,you are unable to execute the script"
fi
结果:
[root@localhost 2-12]# sh test11.sh
sorry,you are unable to execute the script
[root@localhost 2-12]# chmod +x test05.sh
[root@localhost 2-12]# sh test11.sh
you can run the scrip
your HOME directory exits
. .bashrc Downloads .mozilla .ssh
… .cache .esd_auth Music .tcshrc
anaconda-ks.cfg .config .gnome2 Pictures Templates
.bash_history .cshrc .gnome2_private Public testing
.bash_logout Desktop .ICEauthority redhat_iso7.3 Videos
.bash_profile Documents .local shell .viminfo
#!/bin/bash
if [ -O /etc/passwd ]
then
echo "you are the owner if the /etc/passwd file"
else
echo "sorry,you are not the owner of the /etc/passwd file"
fi
结果:
you are the owner if the /etc/passwd file
#!/bin/bash
if [ -G /etc/passwd ]
then
echo "you are the group if the /etc/passwd file"
else
echo "sorry,you are not the group of the /etc/passwd file"
fi
结果:
you are the group if the /etc/passwd file
#!/bin/bash
if [ test01.sh -nt test02.sh ]
then
echo "test01.sh is newer than test02.sh"
else
echo "test02.sh is newer than test01.sh"
fi
if [ test03.sh -ot test04.sh ]
then
echo "test03.sh is older than test04.sh"
else
echo "test04.sh is older than test03.sh"
fi
结果:
test02.sh is newer than test01.sh
test03.sh is older than test04.sh
5. 复合条件测试
if–then语句允许你使用布尔逻辑来组合测试,有两种布尔运算符可用:
[ condition ] && [ condition2 ] # 逻辑与
[ condition ] || [ condition2 ] # 逻辑或
#!/bin/bash
if [ -d $HOME ] && [ -w $HOME/testing ]
then
echo "the file exixts and you can write to it"
else
echo "i cannot write to the file"
fi
结果:
the file exixts and you can write to it
6. if-then的高级特性
使用双尖括号(())
使用方括号[ ]
#!/bin/bash
if [[ $USER == r* ]];then
echo "hello,$USER"
else
echo "sorry,i do not know you"
fi
结果:
hello,root
在test中使用变量建议用双引号包围起来。
test和[]都是命令,一个命令本质上对应一个程序或者一个函数。即使是一个程序,它也有入口函数,例如c语言程序的入口函数是main(),运行c语言程序就从main()函数开始,所以也可以将一个程序等效为一个函数,这样我们就不用再区分函数和程序了,直接将一个命令和一个函数对应起来即可。
有了以上认知,就很容易看透命令的本质了:使用一个命令其实就是调用一个函数,命令后面附带的选项和参数最终都会作为实参传递给函数。
假设test命令对应的函数是func(),使用test -z $str1
命令时,会先将变量$str1
替换成字符串; 如果 $str1
是一个正常的字符串,比如abc123,那么替换后的效果就是test -z abc123
,调用func()函数的形式就是func(-z abc123).test命令后面附带的所有选项和参数会被看成一个整体,并作为实参传递进函数。如果$str1
是一个空的字符串,那么替换后的效果就是test -z,调用func()函数的形式就是func(“-z ”),这就比较奇怪了,因为-z选项没有和参数成对出现,func()在分析时就会出错。
如果我们给$str1
变量加上双引号,当$str1
是空字符串时,test -z “$str1”
就会被替换为test -z “”
,调用func()函数的形式就是func(“-z \”\””)
,很显然,-z选项后面跟的是一个空字符串(\“表示转义字符”),这样func()在分析时就不会出错了。
总结:
test命令比较奇葩,>、<、==只能用来比较字符串,不能用来比较数字,比较数字需要使用-eq、-gt等选项;不管是比较字符串还是数字。test都不支持>=和<=。有经验的程序员需要慢慢习惯test命令的这些奇葩用法。
对于整形数字比较,我建议大家使用(()),(())支持各种运算符,写法也符合数学规则,用起来更加方便。注意:test命令使用标准的数学比较符号来表示字符串比较而用文本代码来表示数值比较,这个细微的特性会被很多程序员理解反了,如果你为数值使用了数学运算符,shell会将他们当成字符串,可能无法产生正确的结果。