一个 if/then 结构测试一系列命令的 退出状态 是否为 0 (因为按照 UNIX 约定,0 表示“成功”),如果是,则执行一个或多个命令。
存在一个专用命令叫做 [ (左方括号 特殊字符)。它是 test 命令的同义词,并且为了效率原因是 内置命令。此命令将其参数视为比较表达式或文件测试,并返回与比较结果相对应的退出状态 (0 表示真,1 表示假)。
在 2.02 版本中,Bash 引入了 [[ ... ]] 扩展测试命令,它以一种对来自其他语言的程序员来说更熟悉的方式执行比较。请注意 [[ 是一个 关键字,而不是一个命令。
Bash 将[[ $a -lt $b ]]视为一个单一元素,它返回一个退出状态。
(( ... )) 和 let ... 结构返回一个 退出状态,这取决于它们评估的算术表达式是否扩展为非零值。这些 算术扩展 结构因此可以用于执行 算术比较。
(( 0 && 1 )) # Logical AND echo $? # 1 *** # And so ... let "num = (( 0 && 1 ))" echo $num # 0 # But ... let "num = (( 0 && 1 ))" echo $? # 1 *** (( 200 || 11 )) # Logical OR echo $? # 0 *** # ... let "num = (( 200 || 11 ))" echo $num # 1 let "num = (( 200 || 11 ))" echo $? # 0 *** (( 200 | 11 )) # Bitwise OR echo $? # 0 *** # ... let "num = (( 200 | 11 ))" echo $num # 203 let "num = (( 200 | 11 ))" echo $? # 0 *** # The "let" construct returns the same exit status #+ as the double-parentheses arithmetic expansion. |
一个 if 可以测试任何命令,而不仅仅是括在方括号内的条件。
if cmp a b &> /dev/null # Suppress output. then echo "Files a and b are identical." else echo "Files a and b differ." fi # The very useful "if-grep" construct: # ----------------------------------- if grep -q Bash file then echo "File contains at least one occurrence of Bash." fi word=Linux letter_sequence=inu if echo "$word" | grep -q "$letter_sequence" # The "-q" option to grep suppresses output. then echo "$letter_sequence found in $word" else echo "$letter_sequence not found in $word" fi if COMMAND_WHOSE_EXIT_STATUS_IS_0_UNLESS_ERROR_OCCURRED then echo "Command succeeded." else echo "Command failed." fi |
最后两个例子由 Stéphane Chazelas 提供。
示例 7-1. 什么是真?
#!/bin/bash
# Tip:
# If you're unsure how a certain condition might evaluate,
#+ test it in an if-test.
echo
echo "Testing \"0\""
if [ 0 ] # zero
then
echo "0 is true."
else # Or else ...
echo "0 is false."
fi # 0 is true.
echo
echo "Testing \"1\""
if [ 1 ] # one
then
echo "1 is true."
else
echo "1 is false."
fi # 1 is true.
echo
echo "Testing \"-1\""
if [ -1 ] # minus one
then
echo "-1 is true."
else
echo "-1 is false."
fi # -1 is true.
echo
echo "Testing \"NULL\""
if [ ] # NULL (empty condition)
then
echo "NULL is true."
else
echo "NULL is false."
fi # NULL is false.
echo
echo "Testing \"xyz\""
if [ xyz ] # string
then
echo "Random string is true."
else
echo "Random string is false."
fi # Random string is true.
echo
echo "Testing \"\$xyz\""
if [ $xyz ] # Tests if $xyz is null, but...
# it's only an uninitialized variable.
then
echo "Uninitialized variable is true."
else
echo "Uninitialized variable is false."
fi # Uninitialized variable is false.
echo
echo "Testing \"-n \$xyz\""
if [ -n "$xyz" ] # More pedantically correct.
then
echo "Uninitialized variable is true."
else
echo "Uninitialized variable is false."
fi # Uninitialized variable is false.
echo
xyz= # Initialized, but set to null value.
echo "Testing \"-n \$xyz\""
if [ -n "$xyz" ]
then
echo "Null variable is true."
else
echo "Null variable is false."
fi # Null variable is false.
echo
# When is "false" true?
echo "Testing \"false\""
if [ "false" ] # It seems that "false" is just a string ...
then
echo "\"false\" is true." #+ and it tests true.
else
echo "\"false\" is false."
fi # "false" is true.
echo
echo "Testing \"\$false\"" # Again, uninitialized variable.
if [ "$false" ]
then
echo "\"\$false\" is true."
else
echo "\"\$false\" is false."
fi # "$false" is false.
# Now, we get the expected result.
# What would happen if we tested the uninitialized variable "$true"?
echo
exit 0 |
练习。 解释上面 示例 7-1 的行为。
if [ condition-true ]
then
command 1
command 2
...
else # Or else ...
# Adds default code block executing if original condition tests false.
command 3
command 4
...
fi |
![]() | 当 if 和 then 在条件测试的同一行时,分号必须终止 if 语句。 if 和 then 都是 关键字。关键字 (或命令) 开始语句,并且在同一行上开始新语句之前,旧语句必须终止。
|
elif是 else if 的缩写。效果是在外部结构中嵌套一个内部 if/then 结构。
if [ condition1 ] then command1 command2 command3 elif [ condition2 ] # Same as else if then command4 command5 else default-command fi |
这if test condition-true结构与以下内容完全等效if [ condition-true ]。碰巧的是,左方括号 [ 是一个 标记 [1],它调用 test 命令。因此,在 if/test 中的右方括号 ] 严格来说不是必需的,但是较新版本的 Bash 需要它。
![]() | test 命令是一个 Bash 内置命令,它测试文件类型并比较字符串。因此,在 Bash 脚本中,test 不会调用外部的/usr/bin/test二进制文件,它是 sh-utils 包的一部分。同样,[ 不会调用/usr/bin/[,它链接到/usr/bin/test.
如果由于某种原因,您希望使用/usr/bin/test在 Bash 脚本中,则使用完整路径名指定它。 |
示例 7-2. test 的等效性,/usr/bin/test[ [ ],以及/usr/bin/[
#!/bin/bash echo if test -z "$1" then echo "No command-line arguments." else echo "First command-line argument is $1." fi echo if /usr/bin/test -z "$1" # Equivalent to "test" builtin. # ^^^^^^^^^^^^^ # Specifying full pathname. then echo "No command-line arguments." else echo "First command-line argument is $1." fi echo if [ -z "$1" ] # Functionally identical to above code blocks. # if [ -z "$1" should work, but... #+ Bash responds to a missing close-bracket with an error message. then echo "No command-line arguments." else echo "First command-line argument is $1." fi echo if /usr/bin/[ -z "$1" ] # Again, functionally identical to above. # if /usr/bin/[ -z "$1" # Works, but gives an error message. # # Note: # This has been fixed in Bash, version 3.x. then echo "No command-line arguments." else echo "First command-line argument is $1." fi echo exit 0 |
![]() | 在 if 之后,test 命令和测试括号 ( [ ] 或 [[ ]] ) 都不是绝对必要的。
类似地,当与 列表结构 结合使用时,测试括号内的条件可以独立存在,而无需 if。
|
(( )) 结构 扩展并评估一个算术表达式。如果表达式评估为零,则返回 退出状态 1,即“假”。非零表达式返回退出状态 0,即“真”。这与之前讨论的 test 和 [ ] 结构形成鲜明对比。
示例 7-3. 使用 (( )) 的算术测试
#!/bin/bash
# arith-tests.sh
# Arithmetic tests.
# The (( ... )) construct evaluates and tests numerical expressions.
# Exit status opposite from [ ... ] construct!
(( 0 ))
echo "Exit status of \"(( 0 ))\" is $?." # 1
(( 1 ))
echo "Exit status of \"(( 1 ))\" is $?." # 0
(( 5 > 4 )) # true
echo "Exit status of \"(( 5 > 4 ))\" is $?." # 0
(( 5 > 9 )) # false
echo "Exit status of \"(( 5 > 9 ))\" is $?." # 1
(( 5 == 5 )) # true
echo "Exit status of \"(( 5 == 5 ))\" is $?." # 0
# (( 5 = 5 )) gives an error message.
(( 5 - 5 )) # 0
echo "Exit status of \"(( 5 - 5 ))\" is $?." # 1
(( 5 / 4 )) # Division o.k.
echo "Exit status of \"(( 5 / 4 ))\" is $?." # 0
(( 1 / 2 )) # Division result < 1.
echo "Exit status of \"(( 1 / 2 ))\" is $?." # Rounded off to 0.
# 1
(( 1 / 0 )) 2>/dev/null # Illegal division by 0.
# ^^^^^^^^^^^
echo "Exit status of \"(( 1 / 0 ))\" is $?." # 1
# What effect does the "2>/dev/null" have?
# What would happen if it were removed?
# Try removing it, then rerunning the script.
# ======================================= #
# (( ... )) also useful in an if-then test.
var1=5
var2=4
if (( var1 > var2 ))
then #^ ^ Note: Not $var1, $var2. Why?
echo "$var1 is greater than $var2"
fi # 5 is greater than 4
exit 0 |
| [1] | 标记 是一个符号或短字符串,附带有特殊含义 (一种 元含义)。在 Bash 中,某些标记 (例如 [ 和 . (点命令)) 可能会扩展为 关键字 和命令。 |