Shell if 入门:让脚本学会“判断”与“选择”
你有没有想过,为什么一个简单的 Shell 脚本能根据不同的条件执行不同的操作?比如,检查某个文件是否存在,如果存在就备份,不存在就提示“文件未找到”。这背后的核心逻辑,就是我们今天要深入探讨的——shell if。
Shell if 不是某种语言的专属功能,而是所有 Shell 脚本中实现“条件判断”的基石。它就像你生活中的“决策树”:遇到红灯停,绿灯行;下雨带伞,晴天晒被。Shell if 让脚本不再只是按顺序执行命令,而是能“思考”、能“选择”。
对于初学者来说,掌握 shell if 是迈向自动化脚本的第一步;对中级开发者而言,它是编写健壮、可维护脚本的关键能力。本文将带你从零开始,一步步掌握 shell if 的语法、实战技巧与常见陷阱。
shell if 的基本语法结构
shell if 的基本结构非常清晰,它由 if、elif(else if)、else 和 fi 组成,其中 fi 是 if 的反写,表示条件块的结束。
if [ 条件判断 ]; then
# 条件为真时执行的命令
echo "条件成立,执行这里"
elif [ 另一个条件 ]; then
# 上一个条件不成立,但这个条件成立时执行
echo "第一个条件不成立,但第二个条件成立"
else
# 所有条件都不成立时执行
echo "所有条件都不成立,走这里"
fi
重点提醒:
if后面的[与条件之间必须有空格,[与]之间也必须有空格。这是 Shell 的语法要求,否则会报错。比如[ -f file.txt ]正确,[ -ffile.txt ]错误。
我们来看一个简单的例子,判断用户输入的数字是否大于 10:
#!/bin/bash
echo "请输入一个数字:"
read num
if [ $num -gt 10 ]; then
echo "你输入的数字大于 10"
elif [ $num -eq 10 ]; then
echo "你输入的数字等于 10"
else
echo "你输入的数字小于 10"
fi
read num:从用户输入读取数据并存入变量num。[ $num -gt 10 ]:判断num是否大于 10。-gt是“greater than”的缩写。elif用于处理多个条件,逻辑清晰。fi必不可少,否则脚本会报语法错误。
常见条件判断操作符详解
在 shell if 中,条件判断依赖于一组操作符,它们分为几类:数值比较、字符串比较、文件测试等。掌握这些操作符,才能写出准确的判断逻辑。
数值比较操作符
| 操作符 | 含义 | 示例 |
|---|---|---|
-eq |
等于 | [ $a -eq $b ] |
-ne |
不等于 | [ $a -ne $b ] |
-gt |
大于 | [ $a -gt $b ] |
-ge |
大于等于 | [ $a -ge $b ] |
-lt |
小于 | [ $a -lt $b ] |
-le |
小于等于 | [ $a -le $b ] |
注意:这些操作符只能用于整数比较。如果变量是小数或字符串,会出错。
字符串比较操作符
| 操作符 | 含义 | 示例 |
|---|---|---|
= |
字符串相等 | [ "$str1" = "$str2" ] |
!= |
字符串不相等 | [ "$str1" != "$str2" ] |
-z |
字符串为空 | [ -z "$str" ] |
-n |
字符串非空 | [ -n "$str" ] |
重要提示:字符串比较时,建议用双引号包裹变量,防止变量为空时报错。
#!/bin/bash
echo "请输入用户名:"
read username
if [ -z "$username" ]; then
echo "用户名不能为空!"
elif [ "$username" = "admin" ]; then
echo "欢迎管理员登录"
else
echo "欢迎用户 $username"
fi
文件测试操作符
| 操作符 | 含义 | 示例 |
|---|---|---|
-f |
是否为普通文件 | [ -f "file.txt" ] |
-d |
是否为目录 | [ -d "/home" ] |
-r |
是否可读 | [ -r "file.txt" ] |
-w |
是否可写 | [ -w "file.txt" ] |
-x |
是否可执行 | [ -x "script.sh" ] |
这些操作符在自动化脚本中非常实用,比如备份前检查源文件是否存在。
实战案例:编写一个备份脚本
让我们用 shell if 实现一个真实场景:一个自动备份脚本。它会检查源文件是否存在,如果存在就备份到目标目录,否则提示错误。
#!/bin/bash
SOURCE_FILE="/home/user/data.txt"
BACKUP_DIR="/backup"
if [ -f "$SOURCE_FILE" ]; then
echo "✅ 源文件存在,开始备份..."
# 检查备份目录是否存在,不存在则创建
if [ ! -d "$BACKUP_DIR" ]; then
echo "📁 备份目录不存在,正在创建..."
mkdir -p "$BACKUP_DIR"
fi
# 执行备份
cp "$SOURCE_FILE" "$BACKUP_DIR/"
echo "✅ 备份成功,文件已保存至 $BACKUP_DIR"
else
echo "❌ 错误:源文件 $SOURCE_FILE 不存在!"
exit 1 # 退出脚本并返回错误码
fi
[ -f "$SOURCE_FILE" ]:判断文件是否存在。! -d "$BACKUP_DIR":!表示“非”,即目录不存在时为真。mkdir -p:创建目录,-p保证父目录也存在。exit 1:脚本执行失败时返回非零退出码,便于其他脚本或任务调度器识别。
这个例子展示了 shell if 的嵌套使用,逻辑清晰,可读性强。
常见陷阱与最佳实践
即使掌握了语法,初学者也容易踩坑。以下是几个高频错误和应对建议。
陷阱 1:变量未加引号
if [ $var -eq 10 ]; then
if [ "$var" -eq 10 ]; then
如果 $var 为空,[ $var -eq 10 ] 会变成 [ -eq 10 ],导致语法错误。加双引号能避免这个问题。
陷阱 2:使用 == 进行字符串比较
在 [ ] 中,== 并不是合法的比较符。你应该用 =。虽然有些 Shell(如 bash)支持 ==,但为了兼容性,建议统一使用 =。
陷阱 3:忘记 fi
这是最常见的语法错误。if 必须配对 fi,否则脚本会报错。
最佳实践建议
- 所有变量都用双引号包裹,如
"$var"。 - 使用
[[ ]]替代[ ](适用于 bash),支持更复杂的判断,如正则匹配。 - 多层判断时使用
elif,避免冗余的if嵌套。 - 为脚本添加注释,提升可维护性。
进阶技巧:使用 [[ ]] 提升判断能力
[[ ]] 是 bash 提供的扩展语法,比 [ ] 更强大。它支持模式匹配、正则表达式等高级功能。
#!/bin/bash
filename="document.pdf"
if [[ "$filename" =~ ^[a-zA-Z]+\.pdf$ ]]; then
echo "文件名符合 PDF 格式"
else
echo "文件名格式不正确"
fi
if [[ "hello world" == h* ]]; then
echo "以 h 开头"
fi
=~用于正则匹配。h*表示以 h 开头的字符串。[[ ]]不需要空格分隔,语法更灵活。
虽然 [[ ]] 不是 POSIX 标准,但在大多数 Linux 系统中都可用,推荐在 bash 脚本中使用。
结语:shell if 是自动化脚本的“大脑”
shell if 不仅是一个语法结构,更是脚本“智能”的起点。它让你的脚本不再只是“死板执行”,而是能根据环境、输入、状态做出响应。
从判断文件是否存在,到控制程序流程,再到实现复杂的自动化任务,shell if 都扮演着核心角色。掌握它,意味着你已经迈入了 Shell 脚本开发的进阶之路。
无论你是想写一个简单的系统检查脚本,还是构建一个完整的部署流程,shell if 都是你不可或缺的工具。多写、多试、多调试,你会发现,原来“判断”这件事,也可以如此优雅而强大。