#7: 判断条件的if else和case
这一节将学习怎么在bash脚本中使用条件语句使脚本在不同的场景下可以实现不同的行为。
通过这种方法,可以构建更高效的脚本,也能在脚本中实现错误检查的能力。
使用 if 语句
决策结构中,最基础的就是if条件判断,bash脚本if语句的基本语法如下:
if [ condition ]; then
your code
fi
The if statement is closed with a fi (reverse of if).
if语句以fi(if倒过来)结束。这是告诉解释器if的代码段到这里结束了。
注意留白!
- 你写的条件和括号两边之间必须有一个空格,否则shell解释器会报错。
- 条件运算符(如:=,==,<=等等)的前后也必须有空格,否则你会看到类似“unary operator expected”的报错。
现在,创建一个示例脚本root.sh,实现只有是root用户运行脚本,才会输出“you are root”:
#!/bin/bash
if [ $(whoami) = 'root' ]; then
echo "You are root"
fi
whoami命令输出用户名,前面的文章中,已经知道了$(command)可以替换命令并提供输出的值被变量或命令。
只有在root用户登陆的时候,条件$(whoami) = "root"才会成立。
不相信?那就运行脚本来看一下吧。

使用if-else语句
上面的演示虽然没有,但是当你用普通用户运行这个root.sh脚本时,它是没有任何输出。先要在if条件的结果为false时运行代码的话,这段代码就需要是在else里面的,如下所示:
#!/bin/bash
if [ $(whoami) = 'root' ]; then
echo "You are root"
else
echo "You are not root"
fi
现在当以普通用户身份运行这个脚本的时候,就可以发现用户不是万能的超级管理员root用户:
sean@debian-12:~$ ./root.sh
You are not root

使用else if语句
要是想要同时测试多个条件(表达式),就会用到elif(else if)语句。
下面的例子中,age.sh脚本接收一个年龄作为参数,并输出与输入年龄相对应的含义信息:
#!/bin/bash
AGE=$1
if [ $AGE -lt 13 ]; then
echo "You are a kid."
elif [ $AGE -lt 20 ]; then
echo "You are a teenager."
elif [ $AGE -lt 65 ]; then
echo "You are an adult."
else
echo "You are an elder."
fi
注意上面的代码,对$AGE变量使用了-lt(小于)作为判断条件运算符。
由之前的文章中,已经知道了怎么向脚本传入参数,多运行几次脚本,来测试不同年龄段的结果:
sean@debian-12:~$ ./age.sh 11
You are a kid.
sean@debian-12:~$ ./age.sh 18
You are a teenager.
sean@debian-12:~$ ./age.sh 44
You are an adult.
sean@debian-12:~$ ./age.sh 70
You are an elder.
总结一下,在if结构中可以有多个elif,但是,只能有一个else,且结尾必须有fi。

嵌套if语句
在一个if语句中使用另一个if这种嵌套形式也是可以的,请看下面weather.sh脚本的例子
#!/bin/bash
TEMP=$1
if [ $TEMP -gt 5 ]; then
if [ $TEMP -lt 15 ]; then
echo "The weather is cold."
elif [ $TEMP -lt 25 ]; then
echo "The weather is nice."
else
echo "The weather is hot."
fi
else
echo "It's freezing outside ..."
fi
这个脚本接收任何温度作为参数,然后显示一条反映天气状况的信息。如果温度大于5,就计算里面嵌套的if-elif语句。同样的,我们多运行几次来看它的工作情况:
sean@debian-12:~$ ./weather.sh 0
It's freezing outside ...
sean@debian-12:~$ ./weather.sh 8
The weather is cold.
sean@debian-12:~$ ./weather.sh 16
The weather is nice.
sean@debian-12:~$ ./weather.sh 30
The weather is hot.

使用case语句
当有时多个if的语句造成阅读困难的时候,可以使用case来替换多个if。case的语法结构如下:
case "variable" in
"pattern1" )
Command … ;;
"pattern2" )
Command … ;;
"pattern2" )
Command … ;;
esac
注意
- 模式后面总是跟着一个空格和右括号
) - 命名内容后面使用两个分号
;;来声明代码端结束,而前面缩进的空格不算强制的。 case语句的代码段结束用esac结尾。
case在处理模式匹配或者正则表达式方面特别有用。请看下面的char.sh脚本:
#!/bin/bash
CHAR=$1
case $CHAR in
[a-z])
echo "Small Alphabet." ;;
[A-Z])
echo "Big Alphabet." ;;
[0-9])
echo "Number." ;;
*)
echo "Special Character."
esac
该脚本接收一个字符作为参数,并显示该字符是大/小写字母、数字还是特殊符号。
sean@debian-12:~$ ./char.sh a
Small Alphabet.
sean@debian-12:~$ ./char.sh Z
Big Alphabet.
sean@debian-12:~$ ./char.sh 7
Number.
sean@debian-12:~$ ./char.sh $
Special Character.
注意,这里使用了通配符(*)来定义默认的分支,它相当于if条件里面的else语句。

判断条件表达式
if语句中有很多的判断条件用于处理数字、字符串、或者文件;根据类型的不同,判断条件的运算符也会有所不同。
下表列出了一些最常用的判断条件表达式:
| 判断表达式 | 等价于 |
|---|---|
| $a -lt $b | $a 小于 $b |
| $a -gt $b | $a 大于 $b |
| $a -le $b | $a 小于等于 $b |
| $a -ge $b | $a 大于等于 $b |
| $a -eq $b | $a 等于 $b |
| $a -ne $b | $a 不等于 $b |
| -e $FILE | $FILE存在 |
| -d $FILE | $FILE存在且是一个目录 |
| -f $FILE | $FILE存在且是一个普通文件 |
| -L $FILE | $FILE存在且是一个软链 |
| $STRING1 = $STRING2 | $STRING1 和 $STRING2 内容一样 |
| $STRING1 != $STRING2 | $STRING1 和 $STRING2 内容不一样 |
| -z $STRING1 | $STRING1 内容是空 |
这些条件判断表达是可以不用死记硬背,通过man test可以从帮组文档中找到它们:
sean@debian-12:~$ man test
最后,我们用一个名为filetype.sh的脚本,来检测一个文件是普通文件还是目录或者软链接:
#!/bin/bash
if [ $# -ne 1 ]; then
echo "Error: Invalid number of arguments"
exit 1
fi
file=$1
if [ -f $file ]; then
echo "$file is a regular file."
elif [ -L $file ]; then
echo "$file is a soft link."
elif [ -d $file ]; then
echo "$file is a directory."
else
echo "$file does not exist"
fi
上面的代码。比之前的代码有一点改进,它会先对传入的参数个数做一个判断,如果没有参数或者有多个参数,就输出一条提示信息并退出,而不会运行剩下的代码。
多运行几次,用不同的类型来测试:
sean@debian-12:~$ ./filetype.sh weather.sh
weather.sh is a regular file.
sean@debian-12:~$ ./filetype.sh /bin
/bin is a soft link.
sean@debian-12:~$ ./filetype.sh /var
/var is a directory.
sean@debian-12:~$ ./filetype.sh
Error: Invalid number of arguments

命令行中只用一行写if else
到目前为止,你所看到和写的if else代码都是基于脚本文件易于阅读的做法.
如果你只是想快速的在shell命令行看输出结果,只运行一次命令,以后不用再使用这个命令,你也可以把if else写成一行。
看看下面的这段代码。
if [ $(whoami) = 'root' ]; then
echo "You are root"
else
echo "You are not root"
fi
你可以像这样在同一行命令中使用它所有的if else语句。
if [ $(whoami) = 'root' ]; then echo "root"; else echo "not root"; fi
你可以直接复制上面的代码在终端中运行,看看它的结果是不是和脚本运行的一样。
基本上,你只需要在命令后面添加分号,然后添加下一个if-else语句。

通过本节的内容,希望您能理解bash的条件语句,让你的bash脚本变得更聪明,使用起来更便捷。
练习题
自己动手做练习可以帮助你记忆刚学到的东西,下面是几到简单的练习题,用到了上面提到的内容。如果您是初学者,建议您可以自己动手做一下。
练习 1:正数还是负数
写一个shell脚本,检查提供的数字是正数还是负数。
难度级别:容易
提示:在这种情况下,0被认为是正数,也就是说,技术上0的非负数。
练习 2:检查给定字符串是否包含子字符串
写一个shell脚本,使用read命令接受来自用户输入的字符串和子字符串。然后检查该字符串是否包含了输入的子字符串并将结果打印出来。
难度级别:容易
提示:使用read命令从用户那里获取输入。
练习 3:检查文件是否存在
编写一个shell脚本,检查文件是否存在,为了简单起见,直接在脚本中保留完整的文件路径。
难度级别:容易
提示:添加判断条件-f用于检查文件。
输出:在脚本中创建一个写死指定路径文件来检查结果。运行脚本并检查,删除文件后再检查。
练习 4:检查给定字符串是否为空
编写shell脚本,提示用户输入一个字符串,然后检查输入的字符串是否为空。
难度级别:容易
提示:使用判断条件-n或-z来检查字符串是否为零
练习 5:是奇数还是偶数
写一个脚本,传入一个正整数的变量,检查该数是奇数还是偶数,并且相应的打印“number x是奇数”或者“number x是偶数”。如果没有参数或者提供了两个以上的参数或者提供的是一个负数,则显示错误信息:“您必须提供一个非负数”。
难度级别:中等
提示:使用模运算符%来检查结果是否为0。
输出:如果输入数字182,应该提示“182是偶数”;如果输入数字23,应该提示“23是奇数”。
练习题答案
答案 1:正数还是负数
写一个shell脚本,检查提供的数字是正数还是负数。
#!/bin/bash
read -p "Enter a number: " number
if [ "$number" -lt 0 ]; then
echo "$number is negative"
else
echo "$number is positive"
fi
答案 2:检查给定字符串是否包含子字符串
写一个shell脚本,使用read命令接受来自用户输入的字符串和子字符串。然后检查该字符串是否包含了输入的子字符串并将结果打印出来。
#!/bin/bash
read -p "Enter the full string: " str
read -p "Enter the substring: " substr
if [[ $str == *"$substr"* ]]; then
echo "Substring found!"
else
echo "Substring not found!"
fi
答案 3:检查文件是否存在
编写一个shell脚本,检查文件是否存在,为了简单起见,直接在脚本中保留完整的文件路径。
#!/bin/bash
#!/bin/bash
FILE=$HOME/simple.txt
if [ -f "$FILE" ]
then
echo "$FILE exists"
else
echo "$FILE doesn't exist"
fi
答案 4:检查给定字符串是否为空
编写shell脚本,提示用户输入一个字符串,然后检查输入的字符串是否为空。
#!/bin/bash
read -p "Enter a string (if you want): " str
if [ -z "$str" ]; then
echo "Empty string"
else
echo "String is not empty"
fi
答案 5:是奇数还是偶数
写一个脚本,传入一个正整数的变量,检查该数是奇数还是偶数,并且相应的打印“number x是奇数”或者“number x是偶数”。如果没有参数或者提供了两个以上的参数或者提供的是一个负数,则显示错误信息:“您必须提供一个非负数”。
#!/bin/bash
if [ $# -ne 1 ] || [ $1 -lt 0 ]; then
echo "You have to provide one non negative number"
elif [ $(($1 % 2)) -eq 0 ]; then
echo "$1 is even"
else
echo "$1 is odd"
fi