Linux Shell 脚本踩坑总结:我被这些问题坑了3次后终于搞懂了
看似简单的东西,反而最容易出错。变量赋值、循环、比较、条件判断,这些基础语法里的坑一个接一个。变量赋值不加空格,等号两边紧紧挨着字符串比较加引号,防止空字符串报错数字比较用 -eq这些专门的符号,别用 =处理文件名用通配符,别用 ls 管道脚本开头加 set -euo pipefail,让错误无所遁形Shell脚本是程序员的必备技能,这些坑早点避开,以后的路才能走得更顺。相关标签:#Linux #
Linux Shell 脚本踩坑总结:我被这些问题坑了3次后终于搞懂了
说实话,之前我总觉得Shell脚本嘛,不就是写几行命令嘛,能有多难?结果现实给了我当头一棒——一个看似简单的自动化脚本,硬是折腾了我一下午,各种奇怪的报错层出不穷。后来我才发现,Shell脚本里的坑是真的多,一个不留神就会踩坑。今天就把我的血泪教训整理出来,希望你们别再重复踩我踩过的坑。
坑1:变量赋值时的空格,让我脚本直接罢工
第一次写自动化脚本时,我想给变量赋值,结果脚本直接报错了。
问题现场:
#!/bin/bash
# 错误的写法
var = "hello"
echo $var
报错信息:
var: command not found
原因分析:
很多人习惯在 = 号两边加空格,觉得这样更"规范"。但在Shell中,= 两边绝对不能有空格!var = "hello" 会被shell解释成命令 var,参数是 = 和 "hello",所以会报 “command not found”。
正确写法:
#!/bin/bash
# 正确的写法
var="hello"
echo $var
# 或者加引号(推荐)
name="shell_script"
echo "脚本名称: $name"
注意事项:
- 变量赋值时,
=前后不能有空格 - 变量名通常用小写,加下划线分隔
- 字符串推荐加双引号,防止空格问题
坑2:for循环处理带空格的文件名,文件竟然"消失"了
有一次我需要遍历目录下的所有文件,写了这么一段脚本:
问题现场:
#!/bin/bash
for file in $(ls /tmp/test/) # 错误写法
do
echo "处理文件: $file"
# 假设这里有更复杂的处理
done
如果目录中有文件名为 “my document.txt”(带空格),这个脚本会把文件名拆成 “my” 和 “document.txt” 两个"文件"来处理,导致实际文件找不到。
原因分析:
$(ls ...) 会按空格分割输出,每遇到一个空格就认为是一个新的"文件"。这不是Shell的问题,是我们自己的写法有问题。
正确写法:
#!/bin/bash
# 方法1:使用 for in 直接匹配
for file in /tmp/test/*
do
echo "处理文件: $file"
done
# 方法2:更安全的方式,设置IFS
#!/bin/bash
IFS=$'\n' # 设置只按换行分割
for file in $(ls /tmp/test/)
do
echo "处理文件: $file"
done
unset IFS # 用完后恢复
# 方法3:find + while(推荐,处理复杂场景)
find /tmp/test/ -type f -name "*.txt" | while read file; do
echo "处理文件: $file"
done
经验总结:
- 尽量避免使用
$(ls ...)来获取文件列表 - 使用通配符
*直接匹配文件 - 复杂场景用
find+while read组合
坑3:字符串比较不加引号,脚本总是判断错误
有一次我需要判断用户输入是否为空,写了这样的判断:
问题现场:
#!/bin/bash
read -p "请输入用户名: " username
if [ $username = "admin" ] # 错误写法
then
echo "欢迎管理员"
else
echo "普通用户"
fi
如果用户直接按回车(输入为空),脚本会报错:
[: =: unary operator expected
原因分析:
当 $username 为空时,[ $username = "admin" ] 会变成 [ = "admin" ],这是非法的。Shell无法理解 = 前面没有操作数。
正确写法:
#!/bin/bash
read -p "请输入用户名: " username
# 方法1:给变量加双引号
if [ "$username" = "admin" ]; then
echo "欢迎管理员"
else
echo "普通用户"
fi
# 方法2:使用 [[ ]](更安全,支持空字符串)
if [[ "$username" = "admin" ]]; then
echo "欢迎管理员"
else
echo "普通用户"
fi
# 方法3:检查字符串是否为空
if [ -z "$username" ]; then
echo "用户名不能为空"
exit 1
fi
注意事项:
- 变量比较时,变量一定要加双引号
- 推荐使用
[[ ]]替代[ ],功能更强大 - 记得检查空字符串情况(
-z和-n)
坑4:整数比较用错了符号,逻辑完全相反
有一次我写了一个检查进程数量的脚本,结果判断逻辑完全反了:
问题现场:
#!/bin/bash
count=$(ps -ef | grep nginx | grep -v grep | wc -l)
# 错误的写法
if [ $count = 0 ]; then
echo "Nginx未运行,启动它"
systemctl start nginx
else
echo "Nginx已在运行"
fi
等等,这个逻辑看起来没问题啊?但是如果 count 不是数字而是字符串,或者比较符号用错了,就会出问题。
原因分析:
在Shell中,= 是字符串比较,-eq 才是整数比较。如果你用 = 比较数字,Shell会按字符串字典序比较,比如 10 < 2 会返回 true(因为 “1” < “2”)。
正确写法:
#!/bin/bash
count=$(ps -ef | grep nginx | grep -v grep | wc -l)
# 整数比较,使用 -eq
if [ "$count" -eq 0 ]; then
echo "Nginx未运行,启动它"
systemctl start nginx
else
echo "Nginx已在运行,当前进程数: $count"
fi
# 其他整数比较符号:
# -eq equal 等于
# -ne not equal 不等于
# -gt greater than 大于
# -lt less than 小于
# -ge greater or equal 大于等于
# -le less or equal 小于等于
常见错误对比:
# ❌ 错误:数字比较用 =
if [ $num = 0 ]; then
# ✅ 正确:数字比较用 -eq
if [ $num -eq 0 ]; then
# ❌ 错误:字符串比较用 -eq
if [ $str -eq "yes" ]; then
# ✅ 正确:字符串比较用 =
if [ "$str" = "yes" ]; then
坑5:命令执行失败还在继续,脚本结果完全不对
我写过一个小工具,用于批量处理日志文件:
问题现场:
#!/bin/bash
# 压缩7天前的日志
find /var/log -name "*.log" -mtime +7 | while read file; do
gzip "$file"
echo "已压缩: $file"
done
# 后续操作
echo "清理完成,发送通知"
send_email "清理完成"
问题在于:如果 gzip 命令执行失败(比如权限问题),脚本不会报错,继续执行下去,你可能根本不知道有文件没处理成功。
原因分析:
默认情况下,Shell脚本中的命令失败不会停止脚本执行,也不会通知你。每个命令都有返回值(0表示成功,非0表示失败),但默认被忽略了。
正确写法:
#!/bin/bash
# 方法1:使用 set -e,遇到错误立即退出
set -e
find /var/log -name "*.log" -mtime +7 | while read file; do
gzip "$file"
echo "已压缩: $file"
done
echo "清理完成"
# 方法2:使用 || 捕获错误
find /var/log -name "*.log" -mtime +7 | while read file; do
gzip "$file" || echo "压缩失败: $file"
done
# 方法3:使用 set -o pipefail,管道中任何一个命令失败都报错
set -o pipefail
# 方法4:检查命令返回值
gzip "$file"
if [ $? -ne 0 ]; then
echo "压缩失败: $file"
exit 1
fi
# 方法5:使用 trap 捕获错误并清理
cleanup() {
echo "发生错误,清理临时文件"
rm -f /tmp/temp_*
}
trap cleanup ERR
最佳实践:
- 脚本开头加上
set -euo pipefail-e:命令失败立即退出-u:使用未定义变量报错-o pipefail:管道中任何一个命令失败都报错
- 重要操作后检查返回值
#!/bin/bash
set -euo pipefail
# 你的脚本逻辑
写在最后
写Shell脚本这么多年,我最大的感悟就是:看似简单的东西,反而最容易出错。变量赋值、循环、比较、条件判断,这些基础语法里的坑一个接一个。
给新手几点建议:
- 变量赋值不加空格,等号两边紧紧挨着
- 字符串比较加引号,防止空字符串报错
- 数字比较用 -eq 这些专门的符号,别用 =
- 处理文件名用通配符,别用 ls 管道
- 脚本开头加 set -euo pipefail,让错误无所遁形
Shell脚本是程序员的必备技能,这些坑早点避开,以后的路才能走得更顺。如果觉得有帮助,点个赞收藏一下,下次遇到类似问题就不怕了。
相关标签:#Linux #Shell #脚本 #运维 #踩坑记录 #自动化
更多推荐

所有评论(0)