shell 字符串比较:从入门到实战
在日常的 Shell 脚本开发中,我们经常需要判断两个字符串是否相等、哪个更大、是否为空,甚至是否包含特定子串。这些操作统称为 shell 字符串比较,是编写自动化脚本的基础能力之一。尤其当你在做系统运维、批量处理文件、配置校验时,熟练掌握字符串比较技巧,能让你事半功倍。
想象一下,你在写一个备份脚本,需要判断当前日期是否与配置文件中设定的备份周期一致。这个“判断是否一致”的过程,本质上就是一次字符串比较。如果连这个都搞不定,脚本就可能误操作,甚至覆盖重要数据。
接下来,我们就从最基础的语法开始,一步步带你掌握 shell 字符串比较的核心用法。
基本比较操作符详解
Shell 提供了多种用于字符串比较的操作符,它们主要分为两类:字符串比较 和 文件属性比较。我们这里重点讲解字符串比较。
使用 = 和 != 进行相等性判断
最常用的字符串比较是判断两个字符串是否相等。在 Bash 中,使用 = 表示“相等”,!= 表示“不相等”。
#!/bin/bash
username="admin"
expected_user="admin"
if [ "$username" = "$expected_user" ]; then
echo "✅ 用户名匹配,授权通过"
else
echo "❌ 用户名不匹配,拒绝访问"
fi
⚠️ 注意:
[是 test 命令的简写,必须与字符串之间有空格。
例如:[ $a = $b ]❌ 错误,[ "$a" = "$b" ]✅ 正确。
变量用双引号包裹,可以防止空值或含空格的字符串导致语法错误。
使用 == 和 !=(Bash 特有)
在 Bash 中,== 与 = 功能相同,但更符合人类直觉。它主要用于 [[ ]] 结构中,推荐在现代脚本中使用。
#!/bin/bash
name="Alice"
if [[ "$name" == "Alice" ]]; then
echo "欢迎,Alice!"
fi
if [[ "$name" != "Bob" ]]; then
echo "你不是 Bob,欢迎访问"
fi
[[ ]]比[ ]更安全,支持通配符、正则匹配,且不会因空值导致语法错误。
在大多数生产环境中,推荐优先使用[[ ]]。
字符串大小比较:< 与 > 的陷阱
你可能会想:字符串也能比大小?当然可以,Shell 会按字典序(lexicographical order)比较字符串,也就是字母表顺序。
例如:apple < banana,因为 a 在 b 前面。
但这里有个关键陷阱:< 和 > 在 Shell 中是重定向符号,直接写会出错!
if [ "apple" < "banana" ]; then
echo "apple 更小"
fi
上面的脚本会报错:bash: [: missing ]'。因为 Shell 把 <当作输入重定向,试图从文件banana` 读取内容。
正确做法:使用 \< 和 \>
要让 Shell 把 < 和 > 当作比较符号,必须用反斜杠转义:
#!/bin/bash
if [ "apple" \< "banana" ]; then
echo "✅ apple 字典序小于 banana"
fi
if [ "zebra" \> "apple" ]; then
echo "✅ zebra 字典序大于 apple"
fi
📌 提示:在
[ ]中,<必须写成\<,>必须写成\>。
在[[ ]]中,不需要转义,可以直接使用<和>。
if [[ "apple" < "banana" ]]; then
echo "apple 在字典序中更靠前"
fi
字符串长度与空值判断
在实际脚本中,判断字符串是否为空或长度是否为 0 是非常常见的需求。
检查字符串是否为空
#!/bin/bash
message=""
if [ -z "$message" ]; then
echo "⚠️ 消息为空,需要填写"
fi
if [ -n "$message" ]; then
echo "消息不为空"
else
echo "消息为空"
fi
-z:字符串为空时返回 true-n:字符串非空时返回 true
小技巧:
[ -z "$var" ]等价于[ "$var" = "" ],但更简洁、更安全。
判断字符串长度
虽然 Shell 没有直接的“长度比较”操作符,但我们可以结合 # 获取变量长度。
#!/bin/bash
password="123456"
length=${#password}
if [ $length -ge 8 ]; then
echo "✅ 密码长度合格"
else
echo "❌ 密码长度不足 8 位"
fi
${#var}是 Bash 的字符串长度语法,返回变量var的字符数。
实际应用案例:用户输入校验脚本
我们来写一个完整的例子,演示如何在真实场景中组合使用多种字符串比较。
#!/bin/bash
echo "请输入用户名(仅支持字母和数字,长度 4-12):"
read username
if [ -z "$username" ]; then
echo "❌ 错误:用户名不能为空"
exit 1
fi
if [ ${#username} -lt 4 ] || [ ${#username} -gt 12 ]; then
echo "❌ 错误:用户名长度必须在 4 到 12 位之间"
exit 1
fi
if [[ ! "$username" =~ ^[a-zA-Z0-9]+$ ]]; then
echo "❌ 错误:用户名只能包含字母和数字"
exit 1
fi
reserved=("admin" "root" "guest")
found=false
for word in "${reserved[@]}"; do
if [ "$username" = "$word" ]; then
echo "❌ 错误:用户名 $username 是保留名,不可用"
found=true
break
fi
done
if [ "$found" = true ]; then
exit 1
fi
echo "🎉 用户名 $username 验证通过,可以使用"
这个脚本展示了:
- 如何组合使用
[[ ]]和[[ =~ ]]进行正则匹配 - 如何用
for循环遍历数组进行比对 - 如何用
exit 1提前终止脚本,避免错误继续执行
高级技巧:通配符与模式匹配
[[ ]] 支持通配符匹配,让你能轻松判断字符串是否符合某种模式。
#!/bin/bash
filename="document.pdf"
if [[ "$filename" == *.pdf ]]; then
echo "这是一个 PDF 文件"
fi
if [[ "$filename" == doc* ]]; then
echo "文件名以 doc 开头"
fi
if [[ "$filename" == *.txt || "$filename" == *.log ]]; then
echo "这是文本或日志文件"
fi
*表示任意字符(包括空字符)
?表示单个字符
[abc]表示匹配 a、b 或 c 中任意一个
常见错误与调试建议
在使用 shell 字符串比较时,有几个高频错误需要特别注意:
| 错误类型 | 原因 | 正确写法 |
|---|---|---|
[ "$a" < "$b" ] |
< 被当作重定向 |
[ "$a" \< "$b" ] 或 [[ "$a" < "$b" ]] |
[ $a = $b ] |
缺少引号 | [ "$a" = "$b" ] |
使用 == 在 [ ] 中 |
不支持 | 改用 = 或使用 [[ ]] |
| 变量未初始化 | 空值导致语法错误 | 始终用双引号包裹变量 |
💡 调试建议:在脚本开头添加
set -euo pipefail,让脚本在错误时立即退出,避免潜藏问题。
总结与进阶建议
通过本文,你应该已经掌握了 shell 字符串比较的核心语法和常见陷阱。关键点总结如下:
- 使用
[[ ]]代替[ ],更安全、功能更强 - 字符串相等用
==或=,不相等用!= - 比较大小时,
<和>必须转义为\<和\>,或在[[ ]]中直接使用 - 判断空值用
-z,判断非空用-n - 长度判断用
${#var},结合-ge、-le等整数比较 - 实际项目中,结合正则、数组、循环,实现复杂逻辑
掌握这些技巧后,你已经具备了编写健壮 Shell 脚本的基础能力。下一步可以学习如何处理文件、解析 JSON、调用外部命令,逐步构建自动化运维系统。
记住:一个成熟的脚本,不是写得越多越好,而是判断得越准越好。每一次字符串比较,都是你对程序逻辑的一次确认。
愿你在 Shell 的世界里,写出简洁、可靠、可维护的代码。