Bash 条件语句
条件语句是编程逻辑的基础,它允许脚本根据特定条件是真(true)还是假(false)来执行不同的代码块。在 Bash 脚本编程中,我们使用 if、then、else、elif 和 fi 关键字来构建这些条件结构。
本章将全面介绍条件语句的语法、不同类型的条件,以及如何在 Bash 脚本中高效地使用它们。
1. if 语句:基础语法
if 语句是 Bash 中最基础的条件执行形式。它允许你仅在特定条件为真时才执行某段代码。 其基本语法如下:
if [ condition ]; then
# 如果条件为真,则执行此处的代码
fiif: 开启条件语句的关键字。[ condition ]: 需要评估的条件。非常重要的一点是,方括号内的条件两边必须要有空格。这里的 [ 实际上是一个命令,它是 test 命令的别名。;: 语句分隔符。当then和条件放在同一行时,必须加上分号。then: 关键字,标记条件为真时要执行的代码块的开始。# 代码...: 要执行的代码块。可以包含一条或多条 Bash 命令。fi: 关键字,代表if语句的结束(if 倒过来拼写)。
示例:检查文件是否存在
#!/bin/bash
file="my_file.txt"
if [ -f "$file" ]; then
echo "文件 '$file' 存在。"
fi在这个例子中:
-f "$file"是条件。-f选项用来测试由变量$file指定的文件是否存在,并且是一个常规文件。- 如果该文件存在,控制台就会打印出 "文件 'my_file.txt' 存在。" 的消息。
2. else 语句
如果 if 语句中的条件为假,else 语句提供了一个备选的代码块来执行。其语法如下:
if [ condition ]; then
# 如果条件为真,执行此处的代码
else
# 如果条件为假,执行此处的代码
fi示例:检查目录是否存在,不存在则创建它
#!/bin/bash
dir="my_directory"
if [ -d "$dir" ]; then
echo "目录 '$dir' 已存在。"
else
echo "目录 '$dir' 不存在。现在开始创建..."
mkdir "$dir"
fi在这个例子中:
-d "$dir"是条件。-d选项用来测试由变量$dir指定的目录是否存在。- 如果目录存在,打印一条消息。否则,打印另一条消息,并执行
mkdir命令来创建该目录。
3. elif 语句
elif(else if 的缩写)语句允许你将多个条件链接在一起。如果前面的 if 或 elif 条件为假,它提供了一种测试额外条件的方法。其语法如下:
if [ condition1 ]; then
# 如果 condition1 为真,执行此代码
elif [ condition2 ]; then
# 如果 condition1 为假且 condition2 为真,执行此代码
else
# 如果 condition1 和 condition2 都为假,执行此代码
fi你可以编写多个 elif 语句来测试一系列条件。
示例:根据不同范围对数字进行评级
#!/bin/bash
num=75
if [ "$num" -gt 90 ]; then
echo "优秀"
elif [ "$num" -gt 70 ]; then
echo "良好"
elif [ "$num" -gt 50 ]; then
echo "及格"
else
echo "有待提高"
fi在这个例子中:
-gt是一个数值比较运算符(表示“大于” / greater than)。- 脚本会依次检查
$num的值符合哪个范围,并打印出相应的消息。
4. 组合条件
Bash 允许你使用逻辑运算符来组合多个条件:
-a或&&: 逻辑与(AND),所有条件都必须为真。-o或||: 逻辑或(OR),至少有一个条件为真。!: 逻辑非(NOT),反转条件的真假。
示例:检查文件是否存在且具有可读性
#!/bin/bash
file="my_file.txt"
if [ -f "$file" -a -r "$file" ]; then
echo "文件 '$file' 存在并且可读。"
else
echo "文件 '$file' 要么不存在,要么不可读。"
fi在这个例子中:
-r "$file"测试文件是否可读。-a运算符确保文件既要存在且要可读,才会执行then代码块。
你也可以使用 && 来编写相同的条件:
if [ -f "$file" ] && [ -r "$file" ]; then
echo "文件 '$file' 存在并且可读。"
else
echo "文件 '$file' 要么不存在,要么不可读。"
fi示例:检查变量是否为空或者包含特定值
#!/bin/bash
variable=""
if [ -z "$variable" ] || [ "$variable" = "default" ]; then
echo "该变量要么为空,要么其值为 'default'。"
fi在这个例子中:
-z "$variable"测试变量是否为空(长度为零)。"$variable" = "default"测试变量是否等于字符串 "default"。注意=号两边要有空格。||运算符确保只要其中任何一个条件为真,就会执行then代码块。
5. 测试命令的替代方案:[[ ]]
Bash 提供了一种使用双括号 [[ ]] 的条件表达式替代语法。与单方括号 [ ] 相比,这种语法具有几个优势:
- 不需要对某些特殊字符进行转义。
- 支持使用
=~进行正则表达式的模式匹配。 - 不会执行单词拆分(Word splitting)和路径名扩展。
示例:结合正则表达式使用 [[ ]]
#!/bin/bash
string="hello world"
if [[ "$string" =~ "world" ]]; then
echo "字符串中包含 'world'。"
fi在这个例子中:
=~是[[ ]]内部的正则表达式匹配运算符。- 条件检查字符串
$string是否包含子字符串 "world"。=~运算符右侧的内容会被解析为扩展正则表达式。
示例:使用 [[ ]] 避免引号带来的问题
#!/bin/bash
file="my file.txt"
# 如果文件不存在,单括号写法可能会报错
if [[ -f "$file" ]]; then
echo "文件存在"
fi
# 上面的代码等价于使用 test ([]) 的下面这段代码:
if test -f "$file"; then
echo "文件存在"
fi使用 [[ ]] 时,你通常不需要担心包含空格的变量的引号问题,不过为了代码的清晰度,加上引号依然是个好习惯。然而,当使用 test 命令(即 [)时,加上引号是必须的,这样可以防止单词拆分和不可预料的行为。
6. 数值比较
在 Bash 中比较数值时,你应该在 [ ] 或 [[ ]] 中使用以下运算符:
-eq: 等于 (Equal to)-ne: 不等于 (Not equal to)-gt: 大于 (Greater than)-ge: 大于或等于 (Greater than or equal to)-lt: 小于 (Less than)-le: 小于或等于 (Less than or equal to)
示例:比较两个数字
#!/bin/bash
num1=10
num2=20
if [ "$num1" -lt "$num2" ]; then
echo "$num1 小于 $num2"
fi7. 字符串比较
比较字符串时,你可以在 [ ] 或 [[ ]] 中使用以下运算符:
=: 等于==: 等于(与=相同)- 在[[ ]]中更常用!=: 不等于-z: 如果字符串为空(长度为零),则为真-n: 如果字符串不为空,则为真
示例:比较两个字符串
#!/bin/bash
str1="hello"
str2="world"
if [ "$str1" != "$str2" ]; then
echo "$str1 不等于 $str2"
fi重要提示: 当在 [ ] 中使用 = 或 != 时,请务必用引号将你的变量括起来。如果变量中包含空格,这能避免单词拆分的问题。在 [[ ]] 中虽然通常不需要引号,但养成加引号的习惯依然很好。
8. 文件存在性与类型检查
Bash 提供了许多用于检查文件是否存在以及文件类型的运算符:
-e: 如果文件存在,则为真 (exists)-f: 如果文件存在且是一个常规文件,则为真 (file)-d: 如果文件存在且是一个目录,则为真 (directory)-r: 如果文件存在且可读,则为真 (readable)-w: 如果文件存在且可写,则为真 (writable)-x: 如果文件存在且可执行,则为真 (executable)-s: 如果文件存在且大小大于零,则为真 (size)
示例:检查文件是否可执行
#!/bin/bash
file="my_script.sh"
if [ -x "$file" ]; then
echo "文件 '$file' 是可执行的。"
else
echo "文件 '$file' 不可执行。"
fi9. 退出状态码
在 Bash 中,每一个命令都会返回一个退出状态码(Exit Status),这是一个整数值,用来表示命令是否执行成功。零 (0) 表示成功,而任何非零值都表示失败。你可以使用 $? 变量来获取上一个执行命令的退出状态码。
示例:检查 mkdir 的退出状态码
#!/bin/bash
mkdir "new_directory"
if [ "$?" -eq 0 ]; then
echo "目录创建成功。"
else
echo "目录创建失败。"
fi在 if 条件中直接使用命令是一种更简洁的写法:
#!/bin/bash
if mkdir "new_directory"; then
echo "目录创建成功。"
else
echo "目录创建失败。"
fi在这个例子中,if 语句直接执行 mkdir 命令。如果 mkdir 成功(返回退出状态码 0),则执行 then 代码块。如果 mkdir 失败(返回非零退出状态码),则执行 else 代码块。这是在 Bash 脚本中检查错误的一种非常常见且高效的方法。
10. 实战:在系统管理脚本中集成错误检查
让我们回顾一下之前模块中的系统管理脚本,并利用条件语句添加错误检查功能。假设这个脚本需要创建一个新的用户账户。
#!/bin/bash
username="newuser"
# 检查用户是否已经存在
if id "$username" &>/dev/null; then
echo "错误:用户 '$username' 已存在。"
exit 1 # 带有错误码退出脚本
fi
# 创建用户
useradd "$username"
# 检查用户创建是否成功
if [ "$?" -ne 0 ]; then
echo "错误:创建用户 '$username' 失败。"
exit 1
fi
echo "用户 '$username' 创建成功。"
# 设置密码(在真实的脚本中,请使用更安全的方法)
echo "$username:password" | chpasswd
# 检查密码是否设置成功
if [ "$?" -ne 0 ]; then
echo "警告:为用户 '$username' 设置密码失败。"
# 我们这里不退出脚本,因为用户已经创建成功了,但我们需要发出警告
fi
echo "用户 '$username' 密码设置完毕。"
exit 0 # 以成功状态退出脚本关键改进点解析:
id "$username" &>/dev/null: 这个命令尝试获取用户信息。&>/dev/null会将标准输出 (stdout) 和标准错误 (stderr) 都重定向到/dev/null,相当于让命令“静音”。如果用户存在,id返回 0(成功);如果用户不存在,返回非零值(失败)。exit 1: 这个命令会以错误码 1 终止脚本运行,表示发生了错误。使用恰当的错误码退出非常重要,这样调用该脚本的其他程序或系统就能探测到失败的情况。- 密码设置警告: 如果设置密码失败,脚本现在会发出警告,但不会退出。这是因为用户其实已经创建成功了,密码设置失败虽然重要,但不是一个需要中断整个脚本的致命错误。在生产环境中,你应该使用更安全的密码管理方案。
exit 0: 脚本最后以成功码 (0) 退出,表示如果没有遇到错误,脚本已顺利执行完毕。
这个示例展示了如何运用条件语句和退出状态码为你的 Bash 脚本添加健壮的错误检查机制,让它们变得更可靠、更容易调试。