写shell脚本看起来简单,几行命令拼在一起就能跑。但实际用起来,稍不注意就会掉进坑里。尤其是刚上手的时候,有些错误看起来莫名其妙,其实都是老问题换了个马甲。
\n\n变量没加引号,空格惹的祸
\n最常见的就是变量赋值和使用时漏了引号。比如:
\nfilename=\"my file.txt\"\nls $filename\n看着没问题,但执行时会变成 ls my file.txt,系统当成两个参数处理,直接报“找不到文件”。正确写法是加上双引号:
ls \"$filename\"\n这样才把整个变量当一个整体传进去。
\n\n忘记转义特殊字符
\n路径里带美元符、反斜杠或者括号,不转义就会出事。比如:
\npath=\"/home/user/myscript($version)\"\necho $path\n这时候shell会尝试解析 $version,哪怕你只是想原样输出。解决办法是该转义就转义:
path=\"/home/user/myscript(\$version)\"\n\n== 在 [ ] 里写成 =
\n在条件判断中,很多人搞混等号的用法。下面这段代码是有问题的:
\nif [ $name == \"admin\" ]; then\n echo \"welcome\"\nfi\n其实在POSIX标准的 [ ] 里,应该用单个等号。双等号是 [[ ]] 才支持的。稳妥起见,要么统一用单等号,要么改用双中括号。
管道后面的变量取不到值
\n这个特别隐蔽。比如你想统计某个进程数量并判断:
\nps aux | grep nginx | wc -l | read count\necho $count\n你会发现 $count 是空的。因为管道会创建子shell,read 的赋值在子shell里完成,主shell拿不到。可以用重定向配合 here string 来绕开:
read count <<< $(ps aux | grep nginx | wc -l)\necho $count\n\n忽略退出状态码
\n脚本里执行一条命令失败了,但后面还在继续跑,结果越错越远。默认情况下,shell不会因为某条命令失败就停下来。可以在脚本开头加上:
\nset -e\n这样一旦有命令返回非零状态,脚本立刻退出。更严格的还可以加 set -u(访问未定义变量报错)和 set -o pipefail(管道中任一环节出错也算失败)。
shebang写错了位置
\n第一行必须是 #! 开头,而且得是文件的第一行第一个字符。如果前面不小心加了空行或者注释,脚本可能用默认shell去解释,导致语法错误。尤其在Mac或Windows上编辑过再传到Linux,换行符也可能导致识别失败。
用find不加处理空格的保护
\n遍历文件时直接这么写:
\nfor file in $(find /path -name \"*.log\"); do\n rm $file\ndone\n如果文件名带空格,又没加引号,删的可能就不是你想删的了。更安全的做法是用 while read 配合 -print0:
find /path -name \"*.log\" -print0 | while IFS= read -r -d '' file; do\n rm \"$file\"\ndone\n\n这些陷阱每个都不难解决,关键是提前知道它们存在。写脚本别图快,稳一点反而省时间。
","seo_title":"shell脚本常见陷阱:新手最容易忽略的几个坑","seo_description":"详解shell脚本中常见的几个陷阱,包括变量引号缺失、特殊字符未转义、管道子shell问题等,帮助新手避开典型错误。","keywords":"shell脚本,shell陷阱,shell脚本错误,shell调试,shell编程"}