在前几章,我们学习了 Shell Script 的基本内容与编辑。那么,如果想要在根据不同情况做一些事情,例如在不同发行版上干不同的事情,或者根据不同参数执行不同的命令,那么就需要用到条件判断语句了。
如果你学习过其它任何的编程语言,那么条件判断语句对你来说应该不会陌生。但是,Shell Script 的条件判断语句的语法十分特别,但是功能都是相似的。
[]
在 Shell Script 中,最常用的条件判断语句就是方括号语句了。方括号语句的语法如下:
[ 运算符 变量 ] # 一个个变量的运算
[ 变量1 运算符 变量2 ] # 两个变量的运算
方括号语句的语法很简单,就是方括号内写上你的条件判断语句,然后在外面写上 []
即可。
方括号其实和
test
命令的功能一模一样,但是方括号可以使代码可读性更高。
注意:方括号语句的语法要求方括号内必须有空格,否则会报错。
方括号判断的结果就是命令的返回值,也就是
$?
,如果返回值为 0,则表示条件判断为真,否则表示条件判断为假,可以使用echo $?
查看。
方括号语句内可以写各种运算符:
运算符 | 含义 | 符号 | 结果为真例子 | 结果为假例子 |
---|---|---|---|---|
-eq | 等于 | = | [ 1 -eq 1 ] | [ 1 -eq 2 ] |
-ne | 不等于 | != | [ 1 -ne 2 ] | [ 1 -ne 1 ] |
-gt | 大于 | > | [ 2 -gt 1 ] | [ 1 -gt 1 ] |
-lt | 小于 | < | [ 1 -lt 2 ] | [ 2 -lt 1 ] |
-ge | 大于等于 | >= | [ 1 -ge 1 ] | [ 1 -ge 2 ] |
-le | 小于等于 | <= | [ 2 -le 2 ] | [ 2 -le 1 ] |
这里的等于和不等于只能用数字,不能使用字符串
运算符 | 含义 | 结果为真例子 | 结果为假例子 |
---|---|---|---|
== | 等于 | [ a == a ] | [ a == b ] |
!= | 不等于 | [ a != b ] | [ 1 != 1 ] |
-n | 字符串长度 > 0 | [ -n abc ] | [ -n '' ] |
-z | 字符串长度 = 0 | [ -z "" ] | [ -z abc ] |
这里等于后面可以是字符串,也可以是数字,因为数字也会被变成字符串。但是比较数字还是建议使用明确的
-eq
。
在字符串比较中,如果传入了一个带空格的字符串,例如 "hello world"
,那么方括号语句会认为这是一个错误,因为方括号语句会认为这是前后两个字符串。所以,引用变量最好使用双引号包裹,例如 [ "$var" == "hello world" ]
。
下文假设当前目录下有一个
file1
文件和一个dir1
目录
运算符 | 含义 | 结果为真例子 | 结果为假例子 |
---|---|---|---|
-e | 存在文件或目录 | [ -e file1 ] | [ -e file2 ] |
-f | 存在指定的文件 | [ -f file1 ] | [ -f dir1 ] |
-d | 存在指定的目录 | [ -d dir1 ] | [ -d file1 ] |
下面大括号内的内容仅方便理解,不是 Bash 命令。
运算符 | 含义 | 结果为真例子 | 结果为假例子 |
---|---|---|---|
-a | 与 | [ 1 -eq 1 -a 2 -eq 2 ] { (1==1) and (2==2) } | [ 1 -eq 1 -a 2 -eq 1 ] { (1==1) and (2==1) } |
-o | 与 | [ 1 -eq 1 -o 2 -eq 1 ] { (1==1) or (2==1) } | [ 1 -eq 2 -o 2 -eq 1 ] { (1==2) or (2==1) } |
! | 非 | [ ! 1 -eq 2 ] | [ ! 1 -eq 1 ] |
就像与运算的示例一样,你可以在一个方括号内写多个表达式。你只需要记住,
-a
和-o
会被最后计算,而且-a
的优先级比-o
高,也就是会先算-a
。
[[]]
双方括号被大多数 Shell 支持(例如在部分系统默认的 sh
中就不支持),用起来比方括号更加方便。但是,在简单判断时,出于兼容性考虑更推荐单方括号。
双方括号的语法和单方括号没有什么区别:
[[ 运算符 变量 ]] # 一个个变量的运算
[[ 变量1 运算符 变量2 ]] # 两个变量的运算
双方括号内可以直接使用上面的所有运算符,也可以使用 >
等数值比较运算符(注意:大于等于不支持)和 &&
(与)、||
(或)等逻辑运算符。
另外,在双方括号中,我们可以使用小括号来指定运算的顺序,就像在数学中一样(在 Bash 中不允许嵌套)。小括号和中括号一样需要加空格。例如:
[[ ( 2 > 1 ) || ( 1 > 2 ) && ( 1 > 1 ) ]]
# 读者可以尝试一下在不使用 Bash 的情况下猜猜运行结果
在双方括号中不需要和单方括号一样,引用字符串变量使用 ""
包裹。例如之前的例子:
[ "$var" == "hello world" ]
# 等价于
[[ $var == "hello world" ]]
if
语句if
语句的语法十分简单:
if 条件语句; then
# 你的任何代码
fi
例如:
# 输入密码到 var 变量中
read -s -p "请输入你的密码:" var
# 判断密码是否是 "password"
if [ $var == "password" ]; then
echo "密码正确"
fi
在条件语句中,可以写
true
和false
,可以直接表示真或者假。也可以写任何命令行,只要程序的返回值为 0 就表示真,非 0 就表示假。这几种参数都不需要在方括号中。
还可以有 elif
和 else
语句:
if 条件语句1; then
# 你的任何代码
elif 条件语句2; then
# 当上面的条件语句都为假,
# 并且当前条件语句为真时
# 执行这里的代码
# elif 可以有多个,不是必须的
else
# 当上面所有条件语句为假时
# 执行这里的代码
# else 也不是必须的
fi
例如:
# 输入用户名到 var 变量中
read -p "请输入你的用户名:" var
# 判断用户是否是 "user1"
if [ $var == "user1" ]; then
echo "User1 你好"
# 判断用户是否是 "user2"
elif [ $var == "user2" ]; then
echo "User2 你好"
# 判断用户是否是 "user3"
elif [ $var == "user3" ]; then
echo "User3 你好"
# 如果都不是
else
echo "找不到该用户"
fi
if
语句的“可玩性”非常高,你已经可以写出很多有趣的脚本了。我们下面还会学习循环和函数,这样你就可以写出更加复杂的脚本了。
case
case
语句和 if
语句类似。但是,如果你有几十条内容,那么 if
就显得不太“优雅”并且难以维护了。
一般来说,3 项以上的
if
就应该写成case
形式了。case
比if
更容易阅读和维护。
下面是 case
的语法: (感觉很奇怪)
case 变量 in
值1)
# 当变量等于值1时
# 执行这里的代码
;;
值2)
# 当变量等于值2时
# 执行这里的代码
;;
*)
# 当变量等于其他值时
# 执行这里的代码
# 不是必须的
;;
esac
注意:每一行最后的双分号
;;
是必须的,表示结束当前分支。如果你比较细心,会发现
esac
就是case
倒过来写,可以用这个来记忆。前面的if
也是一个道理。
例如上面判断用户名的代码就可以改写成:
read -p "请输入你的用户名:" var
case $var in
"user1")
echo "User1 你好"
;;
"user2")
echo "User2 你好"
;;
"user3")
echo "User3 你好"
;;
*)
echo "找不到该用户"
;;
esac
无论是 if
还是 case
,还是后面要学习的循环语句,之间都是可以被随意嵌套的。例如:
read -p "请输入一个数字:" var
if [ $var -gt 5 ]; then
echo "数字大于 5"
if [ $var -gt 10 ]; then
echo "数字大于 10"
fi
else
echo "数字小于或等于 5"
fi
&&
和 ||
&&
和 ||
是 Shell 中的逻辑运算符,用于连接多个条件。
&&
:表示“与”关系,只有当它两边的条件都为真时,整个表达式才为真。||
:表示“或”关系,只要它两边的条件有一个为真,整个表达式就为真。例如:
read -p "请输入你的用户名:" var
read -s -p "请输入你的密码:" var2
if [ $var == "user" ] && [ $var2 == "password" ]; then
echo "登录成功"
else
echo "登录失败"
fi
这两个符号遵循一种叫做“短路”的规则:
&&
符号当前一条命令为假时,后面的命令就不会执行了。
||
符号当前一条命令为真时,后面的命令同样不会执行。“短路”的“可玩性”其实很高,更多的用法就等待读者自行探索了。另外,这两个符号可以像分号一样连接两个命令(遵循“短路”的规则),例如
echo 1&&echo 2
。
这节课的学习压力稍微大一些,但是用处比较大,对于后面的学习有一定帮助。为了更好掌握这个知识点,您可以尝试完成以下作业:
编写一个脚本,判断用户输入的数字是否大于 10。
经典问题:判断一个年份是不是闰年。
提示:可以使用
[ $[ 数字 % 4 ] == 0 ]
来判断一个数是否能被 4 整除。
闰年的定义是:能被 4 整除但不能被 100 整除,或者能被 400 整除的年份。
读者可以尝试使用
if
嵌套,也可以使用&&
||
来实现。
模拟一个软件的安装。复制当前目录下的 some_software
到 /opt/some_software
,但是当 /opt/some_software
存在时,请先删除这个目录。
为上一题的软件编写一个卸载脚本,如果找不到这个目录就显示 软件未安装
,否则提示用户确认后然删除这个目录。
study-area-cn