shell脚本之if语句(1)

许多程序要求对shell脚本中的命令施加一些逻辑流程控制。有一类命令会根据条件使脚本跳过某些命令。这样的命令通常称为结构化命令(structured command)。

结构化命令允许你改变程序执行的顺序。

 

1.使用 if-then 语句

最基本的结构化命令就是 if-then 语句。 if-then 语句有如下格式。

if  command

then

commands

fi

bash shell的 if 语句会运行 if 后面的那个命令。如果该命令的退出状态码是 0(该命令成功运行),位于 then 部分的命令就会被执行。如果该命令的退出状态码是其他值,  then部分的命令就不会被执行,bash shell会继续执行脚本中的下一个命令。 fi 语句用来表示 if-then语句到此结束。

 

if-then 语句的另一种形式:

if command; then

commands

fi

通过把分号放在待求值的命令尾部,就可以将 then 语句放在同一行

 

例一:正确输出

[root@jerry sh]# cat test.sh

#!/bin/bash

#testing the if statement

if pwd

then

    echo "It worked"

fi

脚本在 if 行采用了 pwd 命令。如果命令成功结束, echo 语句就会显示该文本字符串。

[root@jerry sh]# sh test.sh

/root/sh

It worked

shell执行了 if 行中的 pwd 命令。由于退出状态码是 0 ,它就又执行了 then 部分的 echo 语句。

 

例二:错误输出

[root@jerry sh]# cat test.sh

#!/bin/bash

#testing the if statement

if psdwd  #如果psdwd命令

then #执行成功

    echo "It worked"  #则显示It worked 

fi #执行失败

echo "We are outside the if statement"  #则显示We are outside the if statement

[root@jerry sh]# sh test.sh

test.sh: line 3: psdwd: command not found

We are outside the if statement

我们在if 语句行故意放了一个不能执行的命令。由于这是个错误的命令,所以它会产生一个非零的退出状态码,且bash shell会跳过 then 部分的 echo 语句。还要注意,运行if 语句中的那个错误命令所生成的错误消息依然会显示在脚本的输出中。

 

在 then 部分,你可以使用不止一条命令。可以像在脚本中的其他地方一样在这里列出多条命令。bash shell会将这些命令当成一个块,如果 if 语句行的命令的退出状态值为 0 ,所有的命令都会被执行;如果 if 语句行的命令的退出状态不为 0 ,所有的命令都会被跳过。

例三:

[root@jerry sh]# cat test2.sh

#!/bin/bash

#testing multiple commands in the then section

#

testuser=ceshi

#

if grep $testuser /etc/passwd

then

   echo "This is my first command"

   echo "This is my second command"

   echo "I can ecen put in other commands besides echo:"

   ls -a /home/$testuser/.b*

fi

if 语句行使用 grep 命令在/etc/passwd文件中查找某个用户名当前是否在系统上使用。如果有用户使用了那个登录名,脚本会显示一些文本信息并列出该用户HOME目录的bash文件。

[root@jerry sh]# sh test2.sh

ceshi:x:501:501::/home/ceshi:/bin/bash

This is my first command

This is my second command

I can ecen put in other commands besides echo:

/home/ceshi/.bash_history  /home/ceshi/.bash_profile

/home/ceshi/.bash_logout   /home/ceshi/.bashrc

如果将 testuser 变量设置成一个系统上不存在的用户,则什么都不会显示。

 

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 部分中的命令。

 

[root@jerry sh]# cat test2.sh

#!/bin/bash

#testing the else section

#

testuser=cieshi

#

if grep $testuser /etc/passwd

then

   echo "The bash files for user $testuser are:"

   ls -a /home/$testuser/.b*

   echo

else

   echo "The user $testuser does not exist on this system"

   echo

fi

[root@jerry sh]# sh test2.sh

The user cieshi does not exist on this system

这样就更友好了。跟 then 部分一样, else 部分可以包含多条命令。 fi 语句说明 else 部分结束了。

 

3.嵌套 if

有时你需要检查脚本代码中的多种条件。对此,可以使用嵌套的 if-then 语句。

要检查/etc/passwd文件中是否存在某个用户名以及该用户的目录是否尚在,可以使用嵌套的if-then 语句。嵌套的 if-then 语句位于主 if-then-else 语句的 else 代码块中。

[root@jerry sh]# cat test2.sh

#!/bin/bash

#Testing nested ifs

#

testuser=ceshi

#

if grep $testuser /etc/passwd

then

   echo "The bash files for user $testuser are:"

else

   echo "The user $testuser does not exist on this system"

   if ls -d /home/$testuser/

   then

      echo "However,$testuser has a directory"

   fi

fi

[root@jerry sh]# sh test2.sh

ceshi:x:501:501::/home/ceshi:/bin/bash

The user ceshi exists on this system.

 

使用 else 部分的另一种形式: elif 。这样就不用再书写多个 if-then 语句了。 elif 使用另一个 if-then 语句延续 else 部分。

if  command1

then

commands

elif  command2

then

more  commands

fi

elif 语句行提供了另一个要测试的命令,这类似于原始的 if 语句行。如果 elif 后命令的退出状态码是 0 ,则bash会执行第二个 then 语句部分的命令。使用这种嵌套方法,代码更清晰,逻辑更易懂。

 

[root@jerry sh]# cat test2.sh

#!/bin/bash

#Testing nested ifs - use elif

#

testuser=ceishi

#

if grep $testuser /etc/passwd

then

   echo "The user $testuser exists on this system."

#

elif ls -d /home/$testuser

then

   echo "The user $testuser does not exist on this system."

   echo "However, $testuser has a directory."

#

fi

[root@jerry sh]# sh test2.sh

/home/ceishi

The user ceishi does not exist on this system.

However, ceishi has a directory.

注:做本实验的前题是home下创建一个文件

 

甚至可以更进一步,让脚本检查拥有目录的不存在用户以及没有拥有目录的不存在用户。这可以通过在嵌套 elif 中加入一个 else 语句来实现。

[root@jerry sh]# cat test2.sh

#!/bin/bash

#Testing nested ifs - use elif & else

#

testuser=ceishi

#

if grep $testuser /etc/passwd

then

   echo "The user $testuser exists on this system."

#

elif ls -d /home/$testuser

then

   echo "The user $testuser does not exist on this system."

   echo "However, $testuser has a directory."

#

else

   echo "The user $testuser does not exist on this system."

   echo "And, $testuser does not hace a directory."

fi

[root@jerry sh]# sh test2.sh

/home/ceishi

The user ceishi does not exist on this system.

However, ceishi has a directory.

[root@jerry sh]# rm -f /home/ceishi

[root@jerry sh]# sh test2.sh

ls: cannot access /home/ceishi: No such file or directory

The user ceishi does not exist on this system.

And, ceishi does not hace a directory.

在/home/ceishi目录被删除之前,这个测试脚本执行的是 elif 语句,返回零值的退出状态。因此 elif 的 then 代码块中的语句得以执行。删除了/home/ceishi目录之后, elif 语句返回的是非零值的退出状态。这使得 elif 块中的 else 代码块得以执行。

 

在 elif 语句中,紧跟其后的 else 语句属于 elif 代码块。它们并不属于之前的if-then 代码块。

 

可以继续将多个 elif 语句串起来,形成一个大的 if-then-elif 嵌套组合。

if  command1

then

command set 1

elif  command2

then

command set 2

elif  command3

then

command set 3

elif  command4

then

command set 4

fi

每块命令都会根据命令是否会返回退出状态码 0 来执行。记住,bash shell会依次执行 if 语句,只有第一个返回退出状态码 0 的语句中的 then 部分会被执行。

 

4 .test 命令

test 命令提供了在 if-then 语句中测试不同条件的途径。如果 test 命令中列出的条件成立,test 命令就会退出并返回退出状态码 0 。这样 if-then 语句就与其他编程语言中的 if-then 语句以类似的方式工作了。如果条件不成立, test 命令就会退出并返回非零的退出状态码,这使得if-then 语句不会再被执行。

test 命令的格式非常简单。

test condition

condition 是 test 命令要测试的一系列参数和值。当用在 if-then 语句中时, test 命令看起来是这样的。

if test condition

then

commands

fi

如果不写 test 命令的 condition 部分,它会以非零的退出状态码退出,并执行 else 语句块。

[root@jerry sh]# cat test4.sh

#!/bin/bash

#Testing the test command

#

if test

then

   echo "No expression returns a True"

else

   echo "No expression returns a False"

fi

[root@jerry sh]# sh test4.sh

No expression returns a False

 

当你加入一个条件时, test 命令会测试该条件。例如,可以使用 test 命令确定变量中是否有内容。这只需要一个简单的条件表达式。

[root@jerry sh]# cat test4.sh

#!/bin/bash

#Testing the test command

#

my_variable="Fill"

#

if test $my_variable

then

   echo "The $my_variable expression returns a True"

#

else

   echo "The $my_variable expression returns a False"

fi

[root@jerry sh]# sh test4.sh

The Fill expression returns a True

变量 my_variable 中包含有内容( Full ),因此当 test 命令测试条件时,返回的退出状态为 0 。这使得 then 语句块中的语句得以执行。

 

bash shell提供了另一种条件测试方法,无需在 if-then 语句中声明 test 命令。

if [  condition ]

then

commands

fi

方括号定义了测试条件。注意,第一个方括号之后和第二个方括号之前必须加上一个空格,否则就会报错。

test 命令可以判断三类条件:

  数值比较

  字符串比较

  文件比较

 

4.1.数值比较

          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

 

[root@jerry sh]# cat mumeric_test.sh

#!/bin/bash

#Using numeric test ecaluations

#

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 alues are equal"

else

   echo "The values are different"

fi

第一个条件测试:

if [ $value1 -gt 5 ]

测试变量 value1 的值是否大于 5 。第二个条件测试:

if [ $value1 -eq $value2 ]

测试变量 value1 的值是否和变量 value2 的值相等。两个数值条件测试的结果和预想一致。

[root@jerry sh]# sh mumeric_test.sh

The test value 10 is greater than 5

The values are different

 

涉及浮点值时,数值条件测试会有一个限制。

[root@jerry sh]# cat mumeric_test.sh

#!/bin/bash

#Using floating point numbers in test evaluations

#

value1=6.666

#

echo "The test value is $value1"

#

if [ $value1 -gt 5 ]

then

   echo "The test value $value1 is greater than 5"

fi

[root@jerry sh]# sh mumeric_test.sh

The test value is 6.666

mumeric_test.sh: line 8: [: 6.666: integer expression expected

此例,变量 value1 中存储的是浮点值。接着,脚本对这个值进行了测试。显然这里出错了。记住,bash shell只能处理整数。如果你只是要通过 echo 语句来显示这个结果,那没问题。但是,在基于数字的函数中就不行了,例如我们的数值测试条件。最后一行就说明我们不能在test 命令中使用浮点值。

 

4.2.字符串比较

条件测试还允许比较字符串值。但是比较字符串比较烦琐

                       字符串比较测试

     比 较                                              描 述

str1 = str2                       检查 str1 是否和 str2 相同

str1 != str2                      检查 str1 是否和 str2 不同

str1 < str2                       检查 str1 是否比 str2 小

str1 > str2                       检查 str1 是否比 str2 大

-n str1                             检查 str1 的长度是否非0

-z str1                             检查 str1 的长度是否为0

 

1. 字符串相等性

字符串的相等和不等条件不言自明,很容易看出两个字符串值是否相同。

[root@jerry sh]# cat test7.sh

#!/bin/bash

#testubg string equality

testuser=root

#

if [ $USER = $testuser ]

then

   echo "Welcome $testuser"

fi

[root@jerry sh]# sh test7.sh

Welcome root

字符串不等条件也可以判断两个字符串是否有相同的值。

[root@jerry sh]# cat test7.sh

#!/bin/bash

#testubg string equality

testuser=baduser

#

if [ $USER != $testuser ]

then

   echo "This is not $testuser"

else

   echo "Welcome $testuser"

fi

[root@jerry sh]# sh test7.sh

This is not baduser

记住,在比较字符串的相等性时,比较测试会将所有的标点和大小写情况都考虑在内。

 

2. 字符串顺序

要测试一个字符串是否比另一个字符串大就是麻烦的开始。当要开始使用测试条件的大于或小于功能时,就会出现两个经常困扰shell程序员的问题:

  大于号和小于号必须转义,否则shell会把它们当作重定向符号,把字符串值当作文件名;

  大于和小于顺序和 sort 命令所采用的不同。

[root@jerry sh]# cat badtest.sh

#!/bin/bash

#mis-using string comparisons

#

val1=baseba11

val2=hockey

#

if [ $val1 > $val2 ]

then

   echo "$val1 is greater than $val2"

else

   echo "$val1 is less than $val2"

fi

[root@jerry sh]# sh badtest.sh

baseba11 is greater than hockey

[root@jerry sh]# ls -l hockey

-rw-r--r--. 1 root root 0 Dec  9 01:08 hockey

这个脚本中只用了大于号,没有出现错误,但结果是错的。脚本把大于号解释成了输出重定向。因此,它创建了一个名为hockey的文件。由于重定向的顺利完成, test 命令返回了退出状态码 0 , if 语句便以为所有命令都成功结束了。

因此,需要转义符转义大于号

[root@jerry sh]# cat badtest.sh

#!/bin/bash

#mis-using string comparisons

#

val1=baseba11

val2=hockey

#

if [ $val1 \> $val2 ]

then

   echo "$val1 is greater than $val2"

else

   echo "$val1 is less than $val2"

fi

[root@jerry sh]# sh badtest.sh

baseba11 is less than hockey

这样才是真正的比较

 

test 命令和测试表达式使用标准的数学比较符号来表示字符串比较,而用文本代码来表示数值比较。这个细微的特性被很多程序员理解反了。如果你对数值使用了数学运算符号,shell会将它们当成字符串值,可能无法得到正确的结果。

 

3. 字符串大小

-n 和 -z 可以检查一个变量是否含有数据。

[root@jerry sh]# cat test10.sh

#!/bin/bash

#testing string length

va11=testing

va12=''

#

if [ -n $va11 ]

then

   echo "The string '$va11' is not empty"

else

   echo "The string '$va11' is empty"

fi

#

if [ -z $va12 ]

then

   echo "The string '$va12' is empty"

else

   echo "The string '$va12' is not empty"

fi

#

if [ -z $va13]

then

   echo "The string '$va13' is empty"

else

   echo "The string '$va13' is not empty"

fi

[root@jerry sh]# sh test10.sh

The string 'testing' is not empty

The string '' is empty

The string '' is empty

这个例子创建了两个字符串变量。 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 来测试一下变量是否含有值

展开阅读全文

没有更多推荐了,返回首页