1. 使用 if-then 语句
最基本的结构化命令就是if-then语句。if-then语句有如下格式。
if command
then
commands
fi
或者
if command; then
commands
fi
bash shell 的 if 语句会运行 if 后面的那个命令。如果该命令的退出状态码是 0(该命令成功运行),位于 then 部分的命令就会被执行。如果该命令的退出状态码是其他值, then 部分的命令就不会被执行,bash shell 会继续执行脚本中的下一个命令。fi 语句用来表示 if-then 语句到此结束。
$ cat test1.sh
#!/bin/bash
# testing the if statement
if pwd
then
echo "It worked"
fi
$
执行结果
$ ./test1.sh
/home/Christine
It worked
$
在 then 部分,你可以使用不止一条命令。可以像在脚本中的其他地方一样在这里列出多条命令。bash shell 会将这些命令当成一个块,如果 if 语句行的命令的退出状态值为 0,所有的命令都会被执行;如果 if 语句行的命令的退出状态不为 0,所有的命令都会被跳过。
2. if-then-else 语句
if-then-else 语句在语句中提供了另外一组命令。
if command
then
commands
else
commands
fi
当if语句中的命令返回退出状态码 0 时,then 部分中的命令会被执行,这跟普通的 if-then 语句一样。当 if 语句中的命令返回非零退出状态码时,bash shell 会执行 else 部分中的命令。
3. 嵌套 if 语句
elif 使用另一个 if-then 语句延续 else 部分。
if command1
then
commands
elif command2
then
more commands
fi
elif 语句行提供了另一个要测试的命令,这类似于原始的 if 语句行。如果 elif 后命令的退出状态码是 0,则 bash 会执行第二个 then 语句部分的命令。
$ cat test5.sh
#!/bin/bash
# Testing nested ifs - use elif
#
testuser=NoSuchUser
#
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
$
$ ./test5.sh
/home/NoSuchUser
The user NoSuchUser does not exist on this system.
However, NoSuchUser has a directory.
$
可以继续将多个 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。如果条件不成立,test 命令就会退出并返回非零的退出状态码,这使得 if-then 语句不会再被执行。
test 命令的格式非常简单。
test condition
condition 是 test 命令要测试的一系列参数和值。如果不写 test 命令的 condition 部分,它会以非零的退出状态码退出,并执行 else 语句块。
$ cat test6.sh
#!/bin/bash
# Testing the test command
#
if test
then
echo "No expression returns a True"
else
echo "No expression returns a False"
fi
$
$ ./test6.sh
No expression returns a False
$
当你加入一个条件时,test 命令会测试该条件。例如,可以使用 test 命令确定变量中是否有内容。这只需要一个简单的条件表达式。
$ cat test6.sh
#!/bin/bash
# Testing the test command
#
my_variable="Full"
#
if test $my_variable
then
echo "The $my_variable expression returns a True"
#
else
echo "The $my_variable expression returns a False"
fi
$
$ ./test6.sh
The Full expression returns a True
$
bash shell 提供了另一种条件测试方法,无需在 if-then 语句中声明 test 命令。
if [ condition ]
then
commands
fi
方括号定义了测试条件。注意,第一个方括号之后和第二个方括号之前必须加上一个空格,否则就会报错。
test 命令可以判断三类条件:
- 数值比较
- 字符串比较
- 文件比较
4.1 数值比较
记住,bash shell只能处理整数。
比较操作 | 描述 |
---|---|
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 |
$ cat numeric_test.sh
#!/bin/bash
# Using numeric test evaluations
#
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
#
$
# 运行结果
$ ./numeric_test.sh
The test value 10 is greater than 5
The values are different
$
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 |
-
检查字符串相等性
$ cat test7.sh #!/bin/bash # testing string equality testuser=rich # if [ $USER = $testuser ] then echo "Welcome $testuser" fi $ $ ./test7.sh Welcome rich $
-
字符串大小
$ cat test10.sh #!/bin/bash # testing string length val1=testing val2='' # if [ -n $val1 ] then echo "The string '$val1' is not empty" else echo "The string '$val1' is empty" fi # if [ -z $val2 ] then echo "The string '$val2' is empty" else echo "The string '$val2' is not empty" fi # if [ -z $val3 ] then echo "The string '$val3' is empty" else echo "The string '$val3' is not empty" fi $ $ ./test10.sh The string 'testing' is not empty The string '' is empty The string '' is empty $
空的和未初始化的变量会对shell脚本测试造成灾难性的影响。如果不是很确定一个变量的内容,最好在将其用于数值或字符串比较之前先通过-n或-z来测试一下变量是否含有值。
4.3 文件比较
比较 | 描述 |
---|---|
-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 | 检查file1是否比file2旧 (但不会检查文件是否存在) |
$ cat test11.sh
#!/bin/bash
# Look before you leap
#
jump_directory=/home/arthur
#
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
#
$
$ ./test11.sh
The /home/arthur directory does not exist
$
5. 复合条件测试
if-then语句允许你使用布尔逻辑来组合测试。有两种布尔运算符可用:
-
[ condition1 ] && [ condition2 ]
两个条件都必须满足
-
[ condition1 ] || [ condition2 ]
任意一个条件满足
$ cat test22.sh
#!/bin/bash
# testing compound comparisons
#
if [ -d $HOME ] && [ -w $HOME/testing ]
then
echo "The file exists and you can write to it"
else
echo "I cannot write to the file"
fi
$
$ ./test22.sh
I cannot write to the file
$
$ touch $HOME/testing
$
$ ./test22.sh
The file exists and you can write to it
$
6. if-then 高级特性
bash shell 提供了两项可在 if-then 语句中使用的高级特性:
- 用于数学表达式的双括号
- 用于高级字符串处理功能的双方括号
6.1 使用双括号
双括号命令允许你在比较过程中使用高级数学表达式。test 命令只能在比较中使用简单的算术操作。
双括号命令的格式如下:
**(( expression ))**
expression 可以是任意的数学赋值或比较表达式,双括号命令符号如下表所示
符号 | 描述 |
---|---|
val++ | 后增 |
val– | 后减 |
++val | 先增 |
–val | 先减 |
! | 逻辑求反 |
~ | 位求反 |
** | 幂运算 |
<< | 左位移 |
>> | 右位移 |
& | 位布尔和 |
| | 位布尔或 |
&& | 逻辑和 |
|| | 逻辑或 |
可以在if语句中用双括号命令,也可以在脚本中的普通命令里使用来赋值。
$ cat test23.sh
#!/bin/bash
# using double parenthesis
#
val1=10
#
if (( $val1 ** 2 > 90 ))
then
(( val2 = $val1 ** 2 ))
echo "The square of $val1 is $val2"
fi
$
$ ./test23.sh
The square of 10 is 100
$
**注意,不需要将双括号中表达式里的大于号转义。**这是双括号命令提供的另一个高级特性。
6.2 使用双方括号
多数情况下 [ ]
和 [[ ]]
是可以通用的,两者的主要差异是: test
或 [ ]
是符合 POSIX
标准的测试语句,兼容性更强,几乎可以运行再所有的 Shell
解释器中,相比较而言 [[ ]]
仅可运行再特定的几个 Shell
解释器中(如 Bash/Zsh
等)。事实上,目前支持使用 [[ ]]
进行条件测试的解释器已经足够多了。使用 [[ ]]
进行测试判断时甚至可以使用正则表达式。
双方括号命令提供了针对字符串比较的高级特性。双方括号命令的格式如下:
[[ expression ]]
双方括号里的 expression 使用了 test 命令中采用的标准字符串比较。但它提供了 test 命令未提供的另一个特性——模式匹配(pattern matching)。
$ cat test24.sh
#!/bin/bash
# using pattern matching
#
if [[ $USER == r* ]]
then
echo "Hello $USER"
else
echo "Sorry, I do not know you"
fi
$
$ ./test24.sh
Hello rich
$
7. case 命令
case 命令会采用列表格式来检查单个变量的多个值:
case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac
case 命令会将指定的变量与不同模式进行比较。如果变量和模式是匹配的,那么 shell 会执行为该模式指定的命令。可以通过竖线操作符在一行中分隔出多个模式模式。星号会捕获所有与已知模式不匹配的值。
$ cat test26.sh
#!/bin/bash
# using the case command
#
case $USER in
rich | barbara)
echo "Welcome, $USER"
echo "Please enjoy your visit";;
testing)
echo "Special testing account";;
jessica)
echo "Do not forget to log off when you're done";;
*)
echo "Sorry, you are not allowed here";;
esac
$
$ ./test26.sh
Welcome, rich
Please enjoy your visit
$