Linux shell - test
test 命令可以在 if-then 语句中测试不同的条件。如果 test 命令中列出的条件成立,那么 test 命令就会退出并返回退出状态码 0。这样 if-then 语句的工作方式就和其他编程语言中的 if-then 语句差不多了。如果条件不成立,那么 test 命令就会退出并返回非 0 的退出状态码,这使得 if-then 语句不会再被执行。
test 命令的格式非常简单:
test condition
condition 是 test 命令要测试的一系列参数和值。当用在 if-then 语句中时,test 命令看起来如下所示:
if test condition
then
commands
fi
如果不写 test 命令的 condition 部分,则它会以非 0 的退出状态码退出并执行 else 代码块语句:
if test
then
echo "No expression returns a True"
else
echo "No expression returns a False"
fi
# No expression returns a False
如果加入了条件,则 test 命令会测试该条件。例如,可以使用 test 命令确定变量中是否为空。这只需要一个简单的条件表达式:
my_variable="Full"
if test $my_variable
then
echo "The my_variable variable has content and returns a True."
echo "The my_variable variable content is: $my_variable"
else
echo "The my_variable variable doesn't have content,"
echo "and returns a False."
fi
# The my_variable variable has content and returns a True.
# The my_variable variable content is: Full
由于变量 my_variable 中包含内容(Full),因此当 test 命令测试条件时,返回的退出状态码为 0。这使得 then 语句块中的语句得以执行。如果该变量中没有包含内容,就会出现相反的情况。
bash shell 提供了另一种条件测试方式,无须在 if-then 语句中写明 test 命令:
if [ condition ]
then
commands
fi
方括号定义了测试条件。注意,第一个方括号之后和第二个方括号之前必须留有空格,否则就会报错。test 命令和测试条件可以判断 3 类条件。
- 数值比较
- 字符串比较
- 文件比较
数值比较
比较 | 描述 |
---|---|
[ n1 -eq n2 ] | === |
[ n1 -ne n2 ] | !== |
[ n1 -ge n2 ] | >= |
[ n1 -gt n2 ] | > |
[ n1 -le n2 ] | <= |
[ n1 -lt n2 ] | < |
value1=10
value2=11
if [ $value1 -gt 5 ]
then
echo "The test value $value1 is greater than 5."
fi
if [ $value1 -eq $value2 ]
then
echo "The values are equal."
else
echo "The values are different."
fi
# The test value 10 is greater than 5
# The values are different
对于数值比较,bash shell 只能处理整数。尽管可以将浮点值用于某些命令(比如 echo),但它们在条件测试下无法正常工作。
字符串比较
条件测试还允许比较字符串值。
比较 | 描述 |
---|---|
[ str1 = str2 ] | === |
[ str1 != str2 ] | !== |
[ str1 > str2 ] | > |
[ str1 < str2 ] | < |
[ -n str1 ] | str1.length !== 0 |
[ -z str1 ] | str1.length === 0 |
testuser=roger
if [ $testuser = roger ]
then
echo "The testuser variable contains: roger"
else
echo "The testuser variable contains: $testuser"
fi
# The testuser variable contains: roger
testuser=rich
if [ $testuser != roger ]
then
echo "The testuser variable does NOT contain: roger"
else
echo "The testuser variable contains: roger"
fi
# The testuser variable does NOT contain: roger
要测试一个字符串是否大于或小于另一个字符串就开始变得棘手了。
string1=soccer
string2=zorbfootball
if [ $string1 > $string2 ]
then
echo "$string1 is greater than $string2"
else
echo "$string1 is less than $string2"
fi
# soccer is greater than zorbfootball
这个脚本中只用了大于号,虽然没有出现错误,但结果不对。脚本把大于号解释成了输出重定向,因此创建了一个名为 zorbfootball 的文件。由于重定向顺利完成了,测试条件返回了退出状态码 0,if 语句便认为条件成立。
要解决这个问题,需要使用反斜线(\)正确地转义大于号:
string1=soccer
string2=zorbfootball
if [ $string1 \> $string2 ]
then
echo "$string1 is greater than $string2"
else
echo "$string1 is less than $string2"
fi
# soccer is less than zorbfootball
字符串 soccer 小于 zorbfootball,因为在比较的时候使用的是每个字符的 Unicode 编码值。小写字母 s 的编码值是 115,而 z 的编码值是 122。因此,s 小于 z,进而,soccer 小于 zorbfootball。
-n 和-z 可以很方便地用于检查一个变量是否为空:
string1=Soccer
string2=''
#
if [ -n $string1 ]
then
echo "The string '$string1' is NOT empty"
else
echo "The string '$string1' IS empty"
fi
#
if [ -z $string2 ]
then
echo "The string '$string2' IS empty"
else
echo "The string '$string2' is NOT empty"
fi
#
if [ -z $string3 ]
then
echo "The string '$string3' IS empty"
else
echo "The string '$string3' is NOT empty"
fi
# The string 'Soccer' is NOT empty
# The string '' IS empty
# The string '' IS empty
文件比较
文件比较测试很有可能是 shell 编程中最为强大且用得最多的比较形式。它允许测试 Linux 文件系统中文件和目录的状态。
比较 | 描述 |
---|---|
[ -d file ] | file 是否存在且为目录 |
[ -e file ] | file 是否存在 |
[ -f file ] | file 是否存在且为文件 |
[ -r file ] | file 是否存在且可读 |
[ -s file ] | file 是否存在在且非空 |
[ -w file ] | file 是否存在且可写 |
[ -x file ] | file 是否存在且可执行 |
[ -O file ] | file 是否存在且属当前用户所有 |
[ -G file ] | file 是否存在且默认组与当前用户相同 |
[ file1 -nt file2 ] | file1 是否比 file2 新 |
[ file1 -ot file2 ] | file 是否比 file2 旧 |
检查目录
-d 测试会检查指定的目录是否存在于系统中。如果打算将文件写入目录或是准备切换到某个目录,那么先测试一下总是件好事:
jump_directory=/home/roger
if [ -d $jump_directory ]
then
echo "The $jump_directory directory exists."
cd $jump_directory
ls
else
echo "The $jump_directory directory does NOT exist."
fi
# The /home/roger directory does NOT exist.
检查对象是否存在
-e 测试允许在使用文件或目录前先检查其是否存在:
location=$HOME
file_name="Roger"
if [ -d $location ]
then
echo "OK on the $location directory"
echo "Now checking on the file, $file_name..."
if [ -e $location/$file_name ]
then
echo "OK on the file, $file_name."
echo "Updating file's contents."
date >> $location/$file_name
else
echo "File, $location/$file_name, does NOT exist."
echo "Nothing to update."
fi
else
echo "Directory, $location, does NOT exist."
echo "Nothing to update."
fi
# OK on the /home/roger directory
# Now checking on the file, Roger...
# File, /home/roger/Roger, does NOT exist.
# Nothing to update.
检查文件
-e 测试可用于文件和目录。如果要确定指定对象为文件,那就必须使用-f 测试:
object_name=$HOME
echo "The object being checked: $object_name"
if [ -e $object_name ]
then
echo "The object, $object_name, does exist,"
if [ -f $object_name ]
then
echo "and $object_name is a file."
else
echo "and $object_name is a directory."
fi
else
echo "The object, $object_name, does NOT exist."
fi
# The object being checked: /home/roger
# The object, /home/roger, does exist,
# and /home/roger is a directory.
检查是否可读
在尝试从文件中读取数据之前,最好先使用-r 测试检查一下文件是否可读:
pwfile=/etc/shadow
echo
echo "Checking if you can read $pwfile..."
if [ -f $pwfile ]
then
if [ -r $pwfile ]
then
echo "Displaying end of file..."
tail $pwfile
else
echo "Sorry, read access to $pwfile is denied."
fi
else
echo "Sorry, the $pwfile file does not exist."
fi
# Checking if you can read /etc/shadow...
# Sorry, read access to /etc/shadow is denied.
/etc/shadow 文件包含系统用户经过加密后的密码,所以普通用户是无法读取该文件的。-r 测试判断出了该文件不允许读取,因此测试失败,bash shell 执行了 if-then 语句的 else 部分。
检查空文件
应该用-s 测试检查文件是否为空,尤其是当你不想删除非空文件时。要当心,如果-s 测试成功,则说明文件中有数据:
file_name=$HOME/Roger
echo "Checking if $file_name file is empty..."
if [ -f $file_name ]
then
if [ -s $file_name ]
then
echo "The $file_name file exists and has data in it."
echo "Will not remove this file."
else
echo "The $file_name file exits, but is empty."
echo "Deleting empty file..."
rm $file_name
fi
else
echo "The $file_name file does not exist."
fi
# Checking if /home/roger/Roger file is empty...
# The /home/roger/Roger file exists and has data in it.
# Will not remove this file.
检查是否可写
-w 测试可以检查是否对文件拥有可写权限。
item_name=$HOME/Roger
echo
echo "Checking if you can write to $item_name..."
if [ -f $item_name ]
then
if [ -w $item_name ]
then
echo "Writing current time to $item_name"
date +%H%M >> $item_name
else
echo "Sorry, write access to $item_name is denied."
fi
else
echo "Sorry, the $item_name does not exist"
echo "or is not a file."
fi
# Checking if you can write to /home/roger/Roger...
# Writing current time to /home/roger/Roger
检查文件是否可以执行
-x 测试可以方便地判断文件是否有执行权限。虽然可能大多数命令用不到它,但如果想在 shell 脚本中运行大量程序,那就得靠它了。
item_name=$HOME/scripts/can-I-write-to-it.sh
echo
echo "Checking if you can run $item_name..."
if [ -x $item_name ]
then
echo "You can run $item_name."
echo "Running $item_name..."
else
echo "Sorry, you cannot run $item_name."
fi
# Checking if you can run /home/christine/scripts/can-I-write-to-it.sh...
# You can run /home/christine/scripts/can-I-write-to-it.sh.
# Running /home/christine/scripts/can-I-write-to-it.sh...
检查所有权
-O 测试可以轻松地检查你是否是文件的属主:
if [ -O /etc/passwd ]
then
echo "You are the owner of the /etc/passwd file."
else
echo "Sorry, you are NOT /etc/passwd file's owner."
fi
# Sorry, you are NOT /etc/passwd file's owner.
检查默认属组关系
-G 测试可以检查文件的属组,如果与用户的默认组匹配,则测试成功。-G 只会检查默认组而非用户所属的附加组,这会让人有点儿困惑。来看一个例子:
if [ -G $HOME/TestGroupFile ]
then
echo "You are in the same default group as"
echo "the $HOME/TestGroupFile file's group."
else
echo "Sorry, your default group and $HOME/TestGroupFile"
echo "file's group are different."
fi
# You are in the same default group as
# the /home/christine/TestGroupFile file's group.
检查文件日期
最后一组测试用来比较两个文件的创建日期。这在编写软件安装脚本时非常有用。有时,你可不想安装一个比系统中已有文件还要旧的文件。
-nt 测试会判定一个文件是否比另一个文件更新。如果文件较新,那意味着其文件创建日期更晚。-ot 测试会判定一个文件是否比另一个文件更旧。如果文件较旧,则意味着其文件创建日期更早:
if [ $HOME/Downloads/games.rpm -nt $HOME/software/games.rpm ]
then
echo "The $HOME/Downloads/games.rpm file is newer"
echo "than the $HOME/software/games.rpm file."
else
echo "The $HOME/Downloads/games.rpm file is older"
echo "than the $HOME/software/games.rpm file."
fi
# The /home/christine/Downloads/games.rpm file is newer
# than the /home/christine/software/games.rpm file.
复合条件测试
if-then 语句允许使用布尔逻辑将测试条件组合起来。可以使用以下两种布尔运算符。
[ condition1 ] && [ condition2 ]
[ condition1 ] || [ condition2 ]
第一种布尔运算使用布尔运算符 AND 来组合两个条件。要执行 then 部分的命令,两个条件都必须满足。
第二种布尔运算使用 OR 布尔运算符来组合两个条件。如果任意条件为真,那么 then 部分的命令就会执行。
if [ -d $HOME ] && [ -w $HOME/newfile ]
then
echo "The file exists and you can write to it."
else
echo "You cannot write to the file."
fi
# You cannot write to the file.