使用 if-then 结构化命令
在上一篇博文中给出的那些shell脚本里,shell按照命令在脚本中出现的顺序依次进行处理。对顺序操作来说,这已经足够了,因为在这种操作环境下,你想要的就是所有的命令按照正确的顺序执行。然而,并非所有程序都如此操作。
许多程序要求对shell脚本中的命令施加一些逻辑流程控制。有一类命令会根据条件使脚本跳过某些命令。这样的命令通常称为结构化命令(structured command)。
结构化命令允许你改变程序执行的顺序。在bash shell中有不少结构化命令,我们会逐个研究。本节来看一下if-then和case语句。
1、使用if-then 语句
最基本的结构化命令就是if-then语句。if-then语句有如下格式。
1 if command
2 then
3 commands
4 fi
如果你在用其他编程语言的if-then语句,这种形式可能会让你有点困惑。在其他编程语言中,if语句之后的对象是一个等式,这个等式的求值结果为TRUE或FALSE。但bash shell的if语句并不是这么做的。
bash shell的if语句会运行if后面的那个命令。如果该命令的退出状态码(参见上篇博文)是0(该命令成功运行),位于then部分的命令就会被执行。如果该命令的退出状态码是其他值, then部分的命令就不会被执行,bash shell会继续执行脚本中的下一个命令。fi语句用来表示if-then语句到此结束。
这里有个简单的例子可解释这个概念。
1 $ cat if-then1.sh
2 #!/bin/bash
3 #testing the if statement
4 if pwd
5 then
6 echo "it worked"
7 fi
8 $
这个脚本在if行采用了pwd命令。如果命令成功结束,echo语句就会显示该文本字符串。在命令行运行该脚本时,会得到如下结果。
1 $ ./if-then1.sh
2 /home/zhengchuanyu/xiaoyu
3 it worked
4 $
shell执行了if行中的pwd命令。由于退出状态码是0,它就又执行了then部分的echo语句。
下面是另外一个例子。
1 $ cat if-then2.sh
2 #!/bin/bash
3 #testing a bad command
4 if IamNotaCommand
5 then
6 echo "it worked"
7 fi
8
9 echo "we are outside thie if statement"
10 $ chmod a+x if-then2.sh
11 $ ./if-then2.sh
12 ./if-then2.sh: line 3: IamNotaCommand: command not found
13 we are outside thie if statement
14 $
在这个例子中,我们在if语句行故意放了一个不能工作的命令。由于这是个错误的命令,所以它会产生一个非零的退出状态码,且bash shell会跳过then部分的echo语句。还要注意,运行if语句中的那个错误命令所生成的错误消息依然会显示在脚本的输出中。有时你可能不想看到错误信息。在后面的博文中将会讨论如何避免这种情况。
说明 你可能在有些脚本中看到过if-then语句的另一种形式:
if command; then
commands
fi
通过把分号放在待求值的命令尾部,就可以将then语句放在同一行上了,这样看起来更像其他编程语言中的if-then语句。
在then部分,你可以使用不止一条命令。可以像在脚本中的其他地方一样在这里列出多条命令。bash shell会将这些命令当成一个块,如果if语句行的命令的退出状态值为0,所有的命令都会被执行;如果if语句行的命令的退出状态不为0,所有的命令都会被跳过。
1 $ cat if-then3.sh
2 #!/bin/bash
3 # testing multiple commands in the then section
4 #
5 testuser=Christine
6 #
7 if grep $testuser /etc/passwd
8 then
9 echo "This is my first command"
10 echo "This is my second command"
11 echo "I can even put in other commands besides echo:"
12 ls -a /home/$testuser/.b*
13 fi
14 $
if语句行使用grep命令在/etc/passwd文件中查找某个用户名当前是否在系统上使用。如果有用户使用了那个登录名,脚本会显示一些文本信息并列出该用户HOME目录的bash文件。
1 $ ./if-then3.sh
2 Christine:x:501:501:Christine B:/home/Christine:/bin/bash
3 This is my first command
4 This is my second command
5 I can even put in other commands besides echo:
6 /home/Christine/.bash_history /home/Christine/.bash_profile
7 /home/Christine/.bash_logout /home/Christine/.bashrc
8 $
但是,如果将testuser变量设置成一个系统上不存在的用户,则什么都不会显示。
1 $ cat if-then3.sh
2 #!/bin/bash
3 # testing multiple commands in the then section
4 #
5 testuser=NoSuchUser
6 #
7 if grep $testuser /etc/passwd
8 then
9 echo "This is my first command"
10 echo "This is my second command"
11 echo "I can even put in other commands besides echo:"
12 ls -a /home/$testuser/.b*
13 fi
14 $
15 $ ./if-then3.sh
16 $
看起来也没什么新鲜的。如果在这里显示的一些消息可说明这个用户名在系统中未找到,这样可能就会显得更友好。是的,可以用if-then语句的另外一个特性来做到这一点。
2、if-then-else 语句
在if-then语句中,不管命令是否成功执行,你都只有一种选择。如果命令返回一个非零退出状态码,bash shell会继续执行脚本中的下一条命令。在这种情况下,如果能够执行另一组命令就好了。这正是if-then-else语句的作用。
if-then-else语句在语句中提供了另外一组命令。
if command
then
commands
else
commands
fi
当if语句中的命令返回退出状态码0时,then部分中的命令会被执行,这跟普通的if-then语句一样。当if语句中的命令返回非零退出状态码时,bash shell会执行else部分中的命令。
现在可以复制并修改测试脚本来加入else部分。
1 $ cat if-then4.sh
2 #!/bin/sh
3 #testing the else section
4
5 testUser=noSuchUser
6
7 if grep $testUser /etc/passwd
8 then
9 echo "The bash files for user $testuser are:"
10 ls -a /home/$testuser/.b*
11 echo
12 else
13 echo "The user $testuser does not exist on this system."
14 echo
15 fi
16 $
1 $ ./if-then4.sh
2 The user does not exist on this system.
3
4 $
3、嵌套if
有时你需要检查脚本代码中的多种条件。对此,可以使用嵌套的if-then语句。
要检查/etc/passwd文件中是否存在某个用户名以及该用户的目录是否尚在,可以使用嵌套的if-then语句。嵌套的if-then语句位于主if-then-else语句的else代码块中。
1 $ cat if-then5.sh
2 #!/bin/bash
3 # Testing nested ifs
4 #
5 testuser=NoSuchUser
6 #
7 if grep $testuser /etc/passwd
8 then
9 echo "The user $testuser exists on this system."
10 else
11 echo "The user $testuser does not exist on this system."
12 if ls -d /home/$testuser/
13 then
14 echo "However, $testuser has a directory."
15 fi
16 fi
17 $
18 $ ./if-then5.sh
19 The user NoSuchUser does not exist on this system.
20 /home/NoSuchUser/
21 However, NoSuchUser has a directory.
22 $
这个脚本准确无误地发现,尽管登录名已经从/etc/passwd中删除了,但是该用户的目录仍然存在。在脚本中使用这种嵌套if-then语句的问题在于代码不易阅读,很难理清逻辑流程。
可以使用else部分的另一种形式:elif。这样就不用再书写多个if-then语句了。elif使用另一个if-then语句延续else部分。
if command1
then
commands
elif command2
then
more commands
fi
elif语句行提供了另一个要测试的命令,这类似于原始的if语句行。如果elif后命令的退出状态码是0,则bash会执行第二个then语句部分的命令。使用这种嵌套方法,代码更清晰,逻辑更易懂。
4、数值比较
·
数值条件测试可以用在数字和变量上。
1 $ cat numeric_test.sh
2 #!/bin/bash
3 # Using numeric test evaluations
4 #
5 value1=10
6 value2=11
7 #
8 if [ $value1 -gt 5 ]
9 then
10 echo "The test value $value1 is greater than 5"
11 fi
12 #
13 if [ $value1 -eq $value2 ]
14 then
15 echo "The values are equal"
16 else
17 echo "The values are different"
18 fi
19 #
20 $
第一个条件测试:
if [ $value1 -gt 5 ]
测试变量value1的值是否大于5。第二个条件测试:
if [ $value1 -eq $value2 ]
测试变量value1的值是否和变量value2的值相等。两个数值条件测试的结果和预想一致。
1 $ ./numeric_test.sh
2 The test value 10 is greater than 5
3 The values are different
4 $
但是涉及浮点值时,数值条件测试会有一个限制。
1 $ cat floating_point_test.sh
2 #!/bin/bash
3 # Using floating point numbers in test evaluations
4 #
5 value1=5.555
6 #
7 echo "The test value is $value1"
8 #
9 if [ $value1 -gt 5 ]
10 then
11 echo "The test value $value1 is greater than 5"
12 fi
13 #
14 $ ./floating_point_test.sh
15 The test value is 5.555
16 ./floating_point_test.sh: line 8:
17 [: 5.555: integer expression expected
18 $
此例,变量value1中存储的是浮点值。接着,脚本对这个值进行了测试。显然这里出错了。记住,bash shell只能处理整数。如果你只是要通过echo语句来显示这个结果,那没问题。但是,在基于数字的函数中就不行了,例如我们的数值测试条件。最后一行就说明我们不能在test命令中使用浮点值。
5、字符串比较
条件测试还允许比较字符串值。比较字符串比较烦琐
5.1、字符串相等性
字符串的相等和不等条件不言自明,很容易看出两个字符串值是否相同。
1 $ cat test7.sh
2 #!/bin/bash
3 # testing string equality
4 testuser=rich
5 #
6 if [ $USER = $testuser ]
7 then
8 echo "Welcome $testuser"
9 fi
10 $
11 $ ./test7.sh
12 Welcome rich
13 $
字符串不等条件也可以判断两个字符串是否有相同的值。
1 $ cat test8.sh
2 #!/bin/bash
3 # testing string equality
4 testuser=baduser
5 #
6 if [ $USER != $testuser ]
7 then
8 echo "This is not $testuser"
9 else
10 echo "Welcome $testuser"
11 fi
12 $
13 $ ./test8.sh
14 This is not baduser
15 $
记住,在比较字符串的相等性时,比较测试会将所有的标点和大小写情况都考虑在内。
5.2、字符串顺序
要测试一个字符串是否比另一个字符串大就是麻烦的开始。当要开始使用测试条件的大于或小于功能时,就会出现两个经常困扰shell程序员的问题:
- 大于号和小于号必须转义,否则shell会把它们当作重定向符号,把字符串值当作文件名;
- 大于和小于顺序和sort命令所采用的不同。
在编写脚本时,第一条可能会导致一个不易察觉的严重问题。下面的例子展示了shell脚本编程初学者时常碰到的问题。
1 $ cat badtest.sh
2 #!/bin/bash
3 # mis-using string comparisons
4 #
5 val1=baseball
6 val2=hockey
7 #
8 if [ $val1 > $val2 ]
9 then
10 echo "$val1 is greater than $val2"
11 else
12 echo "$val1 is less than $val2"
13 fi
14 $
15 $ ./badtest.sh
16 baseball is greater than hockey
17 $ ls -l hockey
18 -rw-r--r-- 1 rich rich 0 Sep 30 19:08 hockey
19 $
这个脚本中只用了大于号,没有出现错误,但结果是错的。脚本把大于号解释成了输出重定向。因此,它创建了一个名为hockey的文件。由于重定向的顺利完成,test命令返回了退出状态码0,if语句便以为所有命令都成功结束了。
要解决这个问题,就需要正确转义大于号。
1 $ cat test9.sh
2 #!/bin/bash
3 # mis-using string comparisons
4 #
5 val1=baseball
6 val2=hockey
7 #
8 if [ $val1 \> $val2 ]
9 then
10 echo "$val1 is greater than $val2"
11 else
12 echo "$val1 is less than $val2"
13 fi
14 $
15 $ ./test9.sh
16 baseball is less than hockey
17 $
第二个问题更细微,除非你经常处理大小写字母,否则几乎遇不到。sort命令处理大写字母的方法刚好跟test命令相反。让我们在脚本中测试一下这个特性。
1 $ cat test9b.sh
2 #!/bin/bash
3 # testing string sort order
4 val1=Testing
5 val2=testing
6 #
7 if [ $val1 \> $val2 ]
8 then
9 echo "$val1 is greater than $val2"
10 else
11 echo "$val1 is less than $val2"
12 fi
13 $
14 $ ./test9b.sh
15 Testing is less than testing
16 $
17 $ sort testfile
18 testing
19 Testing
20 $
在比较测试中,大写字母被认为是小于小写字母的。但sort命令恰好相反。当你将同样的字符串放进文件中并用sort命令排序时,小写字母会先出现。这是由各个命令使用的排序技术不同造成的。
比较测试中使用的是标准的ASCII顺序,根据每个字符的ASCII数值来决定排序结果。sort命令使用的是系统的本地化语言设置中定义的排序顺序。对于英语,本地化设置指定了在排序顺序中小写字母出现在大写字母前。
说明 test命令和测试表达式使用标准的数学比较符号来表示字符串比较,而用文本代码来表示数值比较。这个细微的特性被很多程序员理解反了。如果你对数值使用了数学运算符号,shell会将它们当成字符串值,可能无法得到正确的结果。
5.3、字符串大小
-n和-z可以检查一个变量是否含有数据。
1 $ cat test10.sh
2 #!/bin/bash
3 # testing string length
4 val1=testing
5 val2=''
6 #
7 if [ -n $val1 ]
8 then
9 echo "The string '$val1' is not empty"
10 else
11 echo "The string '$val1' is empty"
12 fi
13 #
14 if [ -z $val2 ]
15 then
16 echo "The string '$val2' is empty"
17 else
18 echo "The string '$val2' is not empty"
19 fi
20 #
21 if [ -z $val3 ]
22 then
23 echo "The string '$val3' is empty"
24 else
25 echo "The string '$val3' is not empty"
26 fi
27 $
28 $ ./test10.sh
29 The string 'testing' is not empty
30 The string '' is empty
31 The string '' is empty
32 $
这个例子创建了两个字符串变量。val1变量包含了一个字符串,val2变量包含的是一个空字符串。后续的比较如下:
if [ -n $val1 ]
判断val1变量是否长度非0,而它的长度正好非0,所以then部分被执行了。
if [ -z $var2 ]
判断val2变量是否长度为0,而它正好长度为0,所以then部分被执行了。
if [ -z $val3 ]
判断val3变量是否长度为0。这个变量并未在shell脚本中定义过,所以它的字符串长度仍然为0,尽管它未被定义过。
窍门 空的和未初始化的变量会对shell脚本测试造成灾难性的影响。如果不是很确定一个变量的内容,最好在将其用于数值或字符串比较之前先通过-n或-z来测试一下变量是否含有值。
5.4、文件比较
最后一类比较测试很有可能是shell编程中最为强大、也是用得最多的比较形式。它允许你测试Linux文件系统上文件和目录的状态。
5.4.1、检查目录
-d测试会检查指定的目录是否存在于系统中。如果你打算将文件写入目录或是准备切换到某个目录中,先进行测试总是件好事情。
1 $ cat test11.sh
2 #!/bin/bash
3 # Look before you leap
4 #
5 jump_directory=/home/arthur
6 #
7 if [ -d $jump_directory ]
8 then
9 echo "The $jump_directory directory exists"
10 cd $jump_directory
11 ls
12 else
13 echo "The $jump_directory directory does not exist"
14 fi
15 #
16 $
17 $ ./test11.sh
18 The /home/arthur directory does not exist
19 $
示例代码中使用了-d测试条件来检查jump_directory变量中的目录是否存在:若存在,就使用cd命令切换到该目录并列出目录中的内容;若不存在,脚本就输出一条警告信息,然后退出。
5.4.2、检查对象是否存在
这些测试条件使你能够在shell脚本中检查文件系统中的文件。它们经常出现在需要进行文件访问的脚本中。鉴于其使用广泛,我们来逐个看看。
1 $ cat test12.sh
2 #!/bin/bash
3 # Check if either a directory or file exists
4 #
5 location=$HOME
6 file_name="sentinel"
7 #
8 if [ -e $location ]
9 then #Directory does exist
10 echo "OK on the $location directory."
11 echo "Now checking on the file, $file_name."
12 #
13 if [ -e $location/$file_name ]
14 then #File does exist
15 echo "OK on the filename"
16 echo "Updating Current Date..."
17 date >> $location/$file_name
18 #
19 else #File does not exist
20 echo "File does not exist"
21 echo "Nothing to update"
22 fi
23 #
24 else #Directory does not exist
25 echo "The $location directory does not exist."
26 echo "Nothing to update"
27 fi
28 #
29 $
30 $ ./test12.sh
31 OK on the /home/Christine directory.
32 Now checking on the file, sentinel.
33 File does not exist
34 Nothing to update
35 $
36 $ touch sentinel
37 $
38 $ ./test12.sh
39 OK on the /home/Christine directory.
40 Now checking on the file, sentinel.
41 OK on the filename
42 Updating Current Date...
43 $
第一次检查用-e比较来判断用户是否有$HOME目录。如果有,接下来的-e比较会检查sentinel文件是否存在于$HOME目录中。如果不存在,shell脚本就会提示该文件不存在,不需要进行更新。
为确保更新操作能够正常进行,我们创建了sentinel文件,然后重新运行这个shell脚本。这一次在进行条件测试时,$HOME和sentinel文件都存在,因此当前日期和时间就被追加到了文件中。
5.4.3、检查文件
-e比较可用于文件和目录。要确定指定对象为文件,必须用-f比较。
1 $ cat test13.sh
2 #!/bin/bash
3 # Check if either a directory or file exists
4 #
5 item_name=$HOME
6 echo
7 echo "The item being checked: $item_name"
8 echo
9 #
10 if [ -e $item_name ]
11 then #Item does exist
12 echo "The item, $item_name, does exist."
13 echo "But is it a file?"
14 echo
15 #
16 if [ -f $item_name ]
17 then #Item is a file
18 echo "Yes, $item_name is a file."
19 #
20 else #Item is not a file
21 echo "No, $item_name is not a file."
22 fi
23 #
24 else #Item does not exist
25 echo "The item, $item_name, does not exist."
26 echo "Nothing to update"
27 fi
28 #
29 $ ./test13.sh
30 The item being checked: /home/Christine
31 The item, /home/Christine, does exist.
32 But is it a file?
33 No, /home/Christine is not a file.
34 $
这一小段脚本进行了大量的检查!它首先使用-e比较测试$HOME是否存在。如果存在,继续用-f来测试它是不是一个文件。如果它不是文件(当然不会是了),就会显示一条消息,表明这不是一个文件。
5.4.4、检查是否可读
在尝试从文件中读取数据之前,最好先测试一下文件是否可读。可以使用-r比较测试。
1 $ cat test14.sh
2 #!/bin/bash
3 # testing if you can read a file
4 pwfile=/etc/shadow
5 #
6 # first, test if the file exists, and is a file
7 if [ -f $pwfile ]
8 then
9 # now test if you can read it
10 if [ -r $pwfile ]
11 then
12 tail $pwfile
13 else
14 echo "Sorry, I am unable to read the $pwfile file"
15 fi
16 else
17 echo "Sorry, the file $file does not exist"
18 fi
19 $
20 $ ./test14.sh
21 Sorry, I am unable to read the /etc/shadow file
22 $
/etc/shadow文件含有系统用户加密后的密码,所以它对系统上的普通用户来说是不可读的。-r比较确定该文件不允许进行读取,因此测试失败,bash shell执行了if-then语句的else部分。
5.4.5、检查空文件
应该用-s比较来检查文件是否为空,尤其是在不想删除非空文件的时候。要留心的是,当-s比较成功时,说明文件中有数据。
1 $ cat test15.sh
2 #!/bin/bash
3 # Testing if a file is empty
4 #
5 file_name=$HOME/sentinel
6 #
7 if [ -f $file_name ]
8 then
9 if [ -s $file_name ]
10 then
11 echo "The $file_name file exists and has data in it."
12 echo "Will not remove this file."
13 #
14 else
15 echo "The $file_name file exists, but is empty."
16 echo "Deleting empty file..."
17 rm $file_name
18 fi
19 else
20 echo "File, $file_name, does not exist."
21 fi
22 #
23 $ ls -l $HOME/sentinel
24 -rw-rw-r--. 1 Christine Christine 29 Jun 25 05:32 /home/Christine/sentinel
25 $
26 $ ./test15.sh
27 The /home/Christine/sentinel file exists and has data in it.
28 Will not remove this file.
29 $
-f比较测试首先测试文件是否存在。如果存在,由-s比较来判断该文件是否为空。空文件会被删除。可以从ls –l的输出中看出sentinel并不是空文件,因此脚本并不会删除它。
5.4.6、检查是否可写
-w比较会判断你对文件是否有可写权限。脚本test16.sh只是脚本test13.sh的修改版。现在不单检查item_name是否存在、是否为文件,还会检查该文件是否有写入权限。
1 $ cat test16.sh
2 #!/bin/bash
3 # Check if a file is writable.
4 #
5 item_name=$HOME/sentinel
6 echo
7 echo "The item being checked: $item_name"
8 echo
9 [...]
10 echo "Yes, $item_name is a file."
11 echo "But is it writable?"
12 echo
13 #
14 if [ -w $item_name ]
15 then #Item is writable
16 echo "Writing current time to $item_name"
17 date +%H%M >> $item_name
18 #
19 else #Item is not writable
20 echo "Unable to write to $item_name"
21 fi
22 #
23 else #Item is not a file
24 echo "No, $item_name is not a file."
25 fi
26 [...]
27 $
28 $ ls -l sentinel
29 -rw-rw-r--. 1 Christine Christine 0 Jun 27 05:38 sentinel
30 $
31 $ ./test16.sh
32 The item being checked: /home/Christine/sentinel
33 The item, /home/Christine/sentinel, does exist.
34 But is it a file?
35 Yes, /home/Christine/sentinel is a file.
36 But is it writable?
37 Writing current time to /home/Christine/sentinel
38 $
39 $ cat sentinel
40 0543
41 $
变量item_name被设置成$HOME/sentinel,该文件允许用户进行写入。因此当脚本运行时,-w测试表达式会返回非零退出状态,然后执行then代码块,将时间戳写入文件sentinel中。
如果使用chmod关闭文件sentinel的用户 写入权限,-w测试表达式会返回非零的退出状态码,时间戳不会被写入文件。
1 $ chmod u-w sentinel
2 $
3 $ ls -l sentinel
4 -r--rw-r--. 1 Christine Christine 5 Jun 27 05:43 sentinel
5 $
6 $ ./test16.sh
7 The item being checked: /home/Christine/sentinel
8 The item, /home/Christine/sentinel, does exist.
9 But is it a file?
10 Yes, /home/Christine/sentinel is a file.
11 But is it writable?
12 Unable to write to /home/Christine/sentinel
13 $
chmod命令可用来为读者再次回授写入权限。这会使得写入测试表达式返回退出状态码0,并允许一次针对文件的写入尝试。
5.4.7、检查文件是否可以执行
-x 比较是判断特定文件是否有执行权限的一个简单方法。虽然可能大多数命令用不到它,但如果你要在shell脚本中运行大量脚本,它就能发挥作用。
1 $ cat test17.sh
2 #!/bin/bash
3 # testing file execution
4 #
5 if [ -x test16.sh ]
6 then
7 echo "You can run the script: "
8 ./test16.sh
9 else
10 echo "Sorry, you are unable to execute the script"
11 fi
12 $
13 $ ./test17.sh
14 You can run the script:
15 [...]
16 $
17 $ chmod u-x test16.sh
18 $
19 $ ./test17.sh
20 Sorry, you are unable to execute the script
21 $
这段示例shell脚本用-x比较来测试是否有权限执行test16.sh脚本。如果有权限,它会运行这个脚本。在首次成功运行test16.sh脚本后,更改文件的权限。这次,-x比较失败了,因为你已经没有test16.sh脚本的执行权限了。
5.4.8、检查所属关系
-O 比较可以测试出你是否是文件的属主。
1 $ cat test18.sh
2 #!/bin/bash
3 # check file ownership
4 #
5 if [ -O /etc/passwd ]
6 then
7 echo "You are the owner of the /etc/passwd file"
8 else
9 echo "Sorry, you are not the owner of the /etc/passwd file"
10 fi
11 $
12 $ ./test18.sh
13 Sorry, you are not the owner of the /etc/passwd file
14 $
这段脚本用-O比较来测试运行该脚本的用户是否是/etc/passwd文件的属主。这个脚本是运行在普通用户账户下的,所以测试失败了。
5.4.9、检查默认属组关系
-G 比较会检查文件的默认组,如果它匹配了用户的默认组,则测试成功。由于 -G 比较只会检查默认组而非用户所属的所有组,这会叫人有点困惑。这里有个例子。
1 $ cat test19.sh
2 #!/bin/bash
3 # check file group test
4 #
5 if [ -G $HOME/testing ]
6 then
7 echo "You are in the same group as the file"
8 else
9 echo "The file is not owned by your group"
10 fi
11 $
12 $ ls -l $HOME/testing
13 -rw-rw-r-- 1 rich rich 58 2014-07-30 15:51 /home/rich/testing
14 $
15 $ ./test19.sh
16 You are in the same group as the file
17 $
18 $ chgrp sharing $HOME/testing
19 $
20 $ ./test19
21 The file is not owned by your group
22 $
第一次运行脚本时,$HOME/testing文件属于rich组,所以通过了-G比较。接下来,组被改成了sharing组,用户也是其中的一员。但是,-G比较失败了,因为它只比较默认组,不会去比较其他的组。
5.4.10、检查文件日期
最后一组方法用来对两个文件的创建日期进行比较。这在编写软件安装脚本时非常有用。有时候,你不会愿意安装一个比系统上已有文件还要旧的文件。-nt比较会判定一个文件是否比另一个文件新。如果文件较新,那意味着它的文件创建日期更近。-ot比较会判定一个文件是否比另一个文件旧。如果文件较旧,意味着它的创建日期更早。
1 $ cat test20.sh
2 #!/bin/bash
3 # testing file dates
4 #
5 if [ test19.sh -nt test18.sh ]
6 then
7 echo "The test19 file is newer than test18"
8 else
9 echo "The test18 file is newer than test19"
10 fi
11 if [ test17.sh -ot test19.sh ]
12 then
13 echo "The test17 file is older than the test19 file"
14 fi
15 $
16 $ ./test20.sh
17 The test19 file is newer than test18
18 The test17 file is older than the test19 file
19 $
20 $ ls -l test17.sh test18.sh test19.sh
21 -rwxrw-r-- 1 rich rich 167 2014-07-30 16:31 test17.sh
22 -rwxrw-r-- 1 rich rich 185 2014-07-30 17:46 test18.sh
23 -rwxrw-r-- 1 rich rich 167 2014-07-30 17:50 test19.sh
24 $
用于比较文件路径是相对你运行该脚本的目录而言的。如果你要检查的文件已经移走,就会出现问题。另一个问题是,这些比较都不会先检查文件是否存在。试试这个测试。
1 $ cat test21.sh
2 #!/bin/bash
3 # testing file dates
4 #
5 if [ badfile1 -nt badfile2 ]
6 then
7 echo "The badfile1 file is newer than badfile2"
8 else
9 echo "The badfile2 file is newer than badfile1"
10 fi
11 $
12 $ ./test21.sh
13 The badfile2 file is newer than badfile1
14 $
这个小例子演示了如果文件不存在,-nt比较会返回一个错误的结果。在你尝试使用 -nt 或 -ot 比较文件之前,必须先确认文件是存在的。