if/else/elif 分支结构
if 语句根据命令的退出状态码(0 为真,非 0 为假)来决定执行哪个分支。它通常与 test 命令或 [ ]、[[ ]] 条件表达式搭配使用。
基本语法:
if 条件命令; then
命令块
elif 另一个条件; then
命令块
else
命令块
fi
elif 和 else 都是可选的,fi 是结束标记。
常用条件测试:
- 字符串比较:
[ "$a" = "$b" ]、[ -z "$str" ](是否为空)、[ -n "$str" ](是否非空) - 数值比较:
[ "$x" -gt 10 ](大于)、-lt(小于)、-eq(等于)、-ne(不等于) - 文件测试:
[ -f "$file" ](是否存在且为普通文件)、[ -d "$dir" ](是否为目录)、[ -x "$script" ](是否可执行) - 逻辑组合:
[ 条件1 -a 条件2 ](与)、[ 条件1 -o 条件2 ](或),或者使用[[ ]]的&&和||(推荐)
实用示例:
#!/bin/bash
backup_dir="/var/backups"
if [ ! -d "$backup_dir" ]; then
echo "备份目录不存在,正在创建..."
mkdir -p "$backup_dir"
elif [ -z "$(ls -A "$backup_dir")" ]; then
echo "备份目录已存在,但为空。"
else
echo "备份目录已存在,包含 $(ls -1 "$backup_dir" | wc -l) 个文件。"
fi
注意点:
- 变量要用双引号引起来,防止值为空或包含空格时语法错误。
[ ]是test命令的别名,要求操作符两边都有空格(例如[ "$a" = "$b" ]而非["$a"="$b"])。- 在 bash 中,优先使用
[[ ]]:它支持正则匹配=~、模式匹配== pattern,且无需对变量加引号防止分词,更安全方便。
case 多分支结构
当需要将一个变量的值与多个模式进行匹配时,case 比一连串 if/elif 更清晰高效。它常用于处理脚本的启动参数、菜单选择或根据文件名扩展名执行不同操作。
基本语法:
case 变量 in
模式1)
命令块 ;;
模式2)
命令块 ;;
*)
命令块 ;; # 默认分支
esac
- 每个分支末尾用
;;结束。 *匹配所有未命中情况,类似default。- 模式可以使用通配符:
*(任意字符串)、?(任意单个字符)、[abc](字符集)、|(或,如yes|y)
实用示例:服务控制脚本
#!/bin/bash
case "$1" in
start)
echo "正在启动 Web 服务..."
systemctl start nginx
;;
stop)
echo "正在停止 Web 服务..."
systemctl stop nginx
;;
restart|reload)
echo "正在重启 Web 服务..."
systemctl restart nginx
;;
status)
systemctl status nginx
;;
*)
echo "用法: $0 {start|stop|restart|status}"
exit 1
esac
另一个经典例子:根据文件后缀分类处理
for file in *; do
case "$file" in
*.sh) echo "$file 是 Shell 脚本" ;;
*.txt) echo "$file 是文本文件" ;;
*.png|*.jpg|*.gif)
echo "$file 是图片文件" ;;
*) echo "$file 类型未知" ;;
esac
done
注意点:
case内的模式是 shell 的通配符,不是正则表达式,但支持|表示或。- 很长的
if/elif链(超过三四种情况)多半可以用case重构。 - 可以在分支内使用任何命令,包括设置变量、调用函数;需要跳出
case时只需到达;;。
两者选择建议
- if:适用于需要根据命令执行成功与否、复杂逻辑表达式(如组合多个文件测试和数值比较)做决策的场景。
- case:适用于一个变量有多个固定值或通配模式,且每个分支动作差异明显的场景,代码更紧凑易读。
实际脚本中,它们经常配合使用,例如先用 if 检查环境,再用 case 处理用户输入。掌握这两种结构是编写健壮、可读 Shell 脚本的关键一步。