陈斌彬的技术博客

Stay foolish,stay hungry

Bash - 条件判断(原创)

条件测试结构

1.if/then 结构

if/then 结构用来判断命令列表的退出状态码是否为 0,因为0表示成功,如果成功的话,这里应该那么就执行接下来的一个或多个命令。

注意: 这里与 C 语言的等其它语言不同,不能直接使用 0 或者 1 作为判断条件,而应该以 falsetrue代替。以其它大多数语言相反的 true 返回的是0,false 返回的是1

有一个专有命令 [(左中括号,特殊字符)。这个命令与 test 命令等价,由于效率上的考虑,bash 将它作为一个内建命令。

注意: 由于 bash 的语法检查机制,如果在条件测试时只使用一个 [ 将会出现一个错误提示,为了避免这个问题,我们通常将使用一对方括号包含条件测试[]

在版本2.02的 Bash 中, 引入了 "[[ ... ]]" 扩展测试命令,[[ 是一个关键字,并不是一个命令。

if 命令能够测试任何命令,并不仅仅是中括号中的条件。

$ vim test.sh

输入代码:

#!/bin/bash
# 逐字节比较a b两个文件是否相同
if cmp a b &> /dev/null  # 禁止输出.
then echo "Files a and b are identical."
else echo "Files a and b differ."
fi

程序截图:

img

运行:

img

# 非常有用的"if-grep"结构:
# ------------------------
if grep -q Bash file
then echo "File contains at least one occurrence of Bash."
fi

程序截图:

img

运行:

img

word=Linux
letter_sequence=inu
if echo "$word" | grep -q "$letter_sequence"
# "-q" 选项是用来禁止输出的.
then
 echo "$letter_sequence found in $word"
else
 echo "$letter_sequence not found in $word"
fi

程序截图:

img

运行:

img

2.多级比较(应注意与嵌套条件分支区分)

$ vim test.sh

输入代码:

#!/bin/bash
# 这里应该理解为子if/then当做一个整体作为测试条件
if echo "Next *if* is part of the comparison for the first *if*."
   if [[ $comparison = "integer" ]]
     then (( a < b )) # (( 算数表达式 )), 用作算数运算
   else
     [[ $a < $b ]]
   fi
then
 echo '$a is less than $b'
fi

程序截图:

img

注意: ((...))let... 如果运算结果为非0,该语句退出码为0,否则为1; [[...]] 是作为一个单独的语句并且会返回一个退出码

运行代码:

$ bash test.sh

img

3.真假判断

$ vim test.sh

输入代码:

 #!/bin/bash

 #  小技巧:
 #  如果你不能够确定一个特定的条件该如何进行判断,
 #+ 那么就使用if-test结构.

 echo

 echo "Testing \"0\""
 if [ 0 ]      # zero
 then
   echo "0 is true."
 else
   echo "0 is false."
 fi            # 0 为真.

 echo

 echo "Testing \"1\""
 if [ 1 ]      # one
 then
   echo "1 is true."
 else
   echo "1 is false."
 fi            # 1 为真.

 echo

 echo "Testing \"-1\""
 if [ -1 ]     # 负1
 then
   echo "-1 is true."
 else
   echo "-1 is false."
 fi            # -1 为真.

 echo

 echo "Testing \"NULL\""
 if [ ]        # NULL (空状态)
 then
   echo "NULL is true."
 else
   echo "NULL is false."
 fi            # NULL 为假.

 echo

 echo "Testing \"xyz\""
 if [ xyz ]    # 字符串
 then
   echo "Random string is true."
 else
   echo "Random string is false."
 fi            # 随便的一串字符为真.

 echo

 echo "Testing \"\$xyz\""
 if [ $xyz ]   # 判断$xyz是否为null, 但是...
               # 这只是一个未初始化的变量.
 then
   echo "Uninitialized variable is true."
 else
   echo "Uninitialized variable is false."
 fi            # 未定义的初始化为假.

 echo

 echo "Testing \"-n \$xyz\""
 if [ -n "$xyz" ]            # 更加正规的条件检查.
 then
   echo "Uninitialized variable is true."
 else
   echo "Uninitialized variable is false."
 fi            # 未初始化的变量为假.

 echo


 xyz=          # 初始化了, 但是赋null值.

 echo "Testing \"-n \$xyz\""
 if [ -n "$xyz" ]
 then
   echo "Null variable is true."
 else
   echo "Null variable is false."
 fi            # null变量为假.


 echo


 # 什么时候"false"为真?

 echo "Testing \"false\""
 if [ "false" ]              #  看起来"false"只不过是一个字符串而已.
 then
   echo "\"false\" is true." #+ 并且条件判断的结果为真.
 else
   echo "\"false\" is false."
 fi            # "false" 为真.

 echo

 echo "Testing \"\$false\""  # 再来一个, 未初始化的变量.
 if [ "$false" ]
 then
   echo "\"\$false\" is true."
 else
   echo "\"\$false\" is false."
 fi            # "$false" 为假.
               # 现在, 我们得到了预期的结果.


 echo

 exit 0

程序截图:

img

img

运行代码:

$ bash test.sh

img

4.(( )) 结构

(( )) 结构扩展并计算一个算术表达式的值。如果表达式的结果为0,那么返回的退出状态码为1,或者是"假"。而一个非零值的表达式所返回的退出状态码将为0,或者是 "true"

$ vim test.sh

输入代码:

#!/bin/bash
# 算术测试.

# (( ... ))结构可以用来计算并测试算术表达式的结果.
# 退出状态将会与[ ... ]结构完全相反!

(( 0 ))
echo "Exit status of \"(( 0 ))\" is $?."         # 1

(( 1 ))
echo "Exit status of \"(( 1 ))\" is $?."         # 0

(( 5 > 4 ))                                      # 真
echo "Exit status of \"(( 5 > 4 ))\" is $?."     # 0

(( 5 > 9 ))                                      # 假
echo "Exit status of \"(( 5 > 9 ))\" is $?."     # 1

(( 5 - 5 ))                                      # 0
echo "Exit status of \"(( 5 - 5 ))\" is $?."     # 1

(( 5 / 4 ))                                      # 除法也可以.
echo "Exit status of \"(( 5 / 4 ))\" is $?."     # 0

(( 1 / 2 ))                                      # 除法的计算结果 < 1.
echo "Exit status of \"(( 1 / 2 ))\" is $?."     # 截取之后的结果为 0.
                                                # 1

(( 1 / 0 )) 2>/dev/null                          # 除数为0, 非法计算.
#           ^^^^^^^^^^^
echo "Exit status of \"(( 1 / 0 ))\" is $?."     # 1

# "2>/dev/null"起了什么作用?
# 如果这句被删除会怎样?
# 尝试删除这句, 然后在运行这个脚本.

exit 0

程序截图:

img

运行代码:

$ bash test.sh

img

二元比较操作符

1.整数比较

-eq 等于

if [ "$a" -eq "$b" ]

-ne 不等于

if [ "$a" -ne "$b" ]

-gt 大于

if [ "$a" -gt "$b" ]

-ge 大于等于

if [ "$a" -ge "$b" ]

-lt 小于

if [ "$a" -lt "$b" ]

-le 小于等于

if [ "$a" -le "$b" ]

< 小于(在双括号中使用)

(("$a" < "$b"))

<= 小于等于(在双括号中使用)

(("$a" <= "$b"))

大于(在双括号中使用)

(("$a" > "$b"))

= 大于等于(在双括号中使用)

(("$a" >= "$b"))

2.字符串比较

= 等于

if [ "$a" = "$b" ]

== 等于,与 = 等价

if [ "$a" == "$b" ]

!= 不等号

if [ "$a" != "$b" ]

< 小于,按照 ASCII 字符进行排序

if [[ "$a" < "$b" ]]
if [ "$a" \< "$b" ]

注意 "<" 使用在 [ ] 结构中的时候需要被转义

大于,按照 ASCII 字符进行排序

if [[ "$a" > "$b" ]]
if [ "$a" \> "$b" ]

注意 “>” 使用在 [ ] 结构中的时候需要被转义

-z 字符串为 “null” ,意思就是字符串长度为零

-n 字符串不为 “null”

3.算术比较与字符串比较

$ vim test.sh

输入代码:

#!/bin/bash

a=4
b=5

#  这里的"a"和"b"既可以被认为是整型也可被认为是字符串.
#  这里在算术比较与字符串比较之间是容易让人产生混淆,
#+ 因为Bash变量并不是强类型的.

#  Bash允许对于变量进行整形操作与比较操作.
#+ 但前提是变量中只能包含数字字符.
#  不管怎么样, 还是要小心.

echo

if [ "$a" -ne "$b" ]
then
 echo "$a is not equal to $b"
 echo "(arithmetic comparison)"
fi

echo

if [ "$a" != "$b" ]
then
 echo "$a is not equal to $b."
 echo "(string comparison)"
 #     "4"  != "5"
 # ASCII 52 != ASCII 53
fi

# 在这个特定的例子中, "-ne"和"!="都可以.

echo

exit 0

程序截图:

img

运行:

img

4.检查字符串是否为 null

$ vim test.sh

输入代码:

#!/bin/bash
#  str-test.sh: 检查null字符串和未引用的字符串,

# 使用   if [ ... ]

# 如果字符串并没有被初始化, 那么它里面的值未定义.
# 这种状态被称为"null" (注意这与零值不同).

if [ -n $string1 ]    # $string1 没有被声明和初始化.
then
 echo "String \"string1\" is not null."
else  
 echo "String \"string1\" is null."
fi  
# 错误的结果.
# 显示$string1为非null, 虽然这个变量并没有被初始化.

echo

程序截图:

img

运行:

img

if [ -n "$string1" ]  # 这次$string1被引号扩起来了.
then
 echo "String \"string1\" is not null."
else  
 echo "String \"string1\" is null."
fi                    # 注意一定要将引用的字符放到中括号结构中!

echo

程序截图:

img

运行:

img

if [ $string1 ]       # 这次, 就一个$string1, 什么都不加.
then
 echo "String \"string1\" is not null."
else  
 echo "String \"string1\" is null."
fi  
# 这种情况运行的非常好.
# [ ] 测试操作符能够独立检查string是否为null.
# 然而, 使用("$string1")是一种非常好的习惯.
#
# 就像Stephane Chazelas所指出的,
#    if [ $string1 ]    只有一个参数, "]"
#    if [ "$string1" ]  有两个参数, 一个是空的"$string1", 另一个是"]"

echo

程序截图:

img

运行:

img

string1=initialized

if [ $string1 ]       # 再来, 还是只有$string1, 什么都不加.
then
 echo "String \"string1\" is not null."
else  
 echo "String \"string1\" is null."
fi  
# 再来试一下, 给出了正确的结果.
# 再强调一下, 使用引用的("$string1")还是更好一些, 原因我们上边已经说过了.

程序截图:

img

运行:

img

string1="a = b"

if [ $string1 ]       # 再来, 还是只有$string1, 什么都不加.
then
 echo "String \"string1\" is not null."
else  
 echo "String \"string1\" is null."
fi  
# 未引用的"$string1", 这回给出了错误的结果!

exit 0

程序截图:

img

运行:

img

5.compound 和 comparison

-a 逻辑与 exp1 -a exp2 如果表达式 exp1 和 exp2 都为真的话,那么结果为真。

-o 逻辑或 exp1 -o exp2 如果表达式 exp1 和 exp2 中至少有一个为真的话,那么结果为真。

注意:这与 Bash 中的比较操作符 && 和 || 非常相像,但是这个两个操作符是用在双中括号结构中的。

[[ condition1 && condition2 ]]

-o-a 操作符一般都是和 test 命令或者是单中括号结构一起使用的

if [ "$exp1" -a "$exp2" ]