极简工具箱

免费在线工具 · 本地计算 · 无需上传

Shell 脚本怎么写才不出事:set -e 与引号

脚本跑了一半出错却继续执行,最后删错了目录;变量里有空格导致命令参数错位。Shell 脚本的坑,八成能用「开头三行 + 到处加引号」解决。

广告位(百度联盟)

一、开头三行

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

逐条解释:

这三行能挡掉大部分「脚本把事搞砸」的事故。

二、变量与参数必须加引号

# 危险:文件名含空格会被拆成两个参数
cp $file /backup/

# 安全
cp "$file" /backup/

"$var" 与 $var 的区别在于「是否保留为一个整体」。特别注意:

三、$@、$*、$#

echo "$#"        # 参数个数
echo "$@"        # 所有参数,各自独立(推荐)
echo "$*"        # 所有参数,拼成一个字符串
echo "$1"        # 第一个参数

"$@" 会保留每个参数的边界,"$*" 会用 IFS 拼起来。遍历参数用:

for arg in "$@"; do
    echo "$arg"
done

**不要写 for arg in $***,含空格的参数会被拆开。

默认值与校验:

NAME="${1:-default}"          # 为空则用默认值
: "${API_KEY:?必须设置 API_KEY}"  # 为空则报错退出

四、[ ] 还是 [[ ]]

[[ ]] 是 bash 的扩展,更安全、更好用:

场景[ ][[ ]]
字符串比较[ "$a" = "$b" ][[ $a == $b ]]
模式匹配不支持[[ $a == pre* ]]
正则不支持[[ $a =~ ^[0-9]+$ ]]
逻辑运算-a / -o(易错)&& / ``
空变量必须加引号不加强制但要小心

用 [[ ]] 时变量可以不引号,但养成加引号的习惯仍然更稳。POSIX sh 环境(如 Alpine 的 /bin/sh)不支持 [[ ]],脚本要兼容就老老实实用 [ ]。

五、函数与返回值

backup() {
    local src="$1"
    local dst="$2"
    [ -d "$src" ] || { echo "源目录不存在: $src" >&2; return 1; }
    tar -czf "$dst" "$src"
}

if ! backup /data /tmp/data.tgz; then
    echo "备份失败" >&2
    exit 1
fi

要点:

六、调试

bash -x script.sh        # 打印每条执行的命令
bash -n script.sh        # 只做语法检查,不执行
set -x / set +x          # 在脚本内局部开启/关闭

配合 PS4='+ $LINENO: ' 可以显示行号,定位更快。

另一个技巧是 shellcheck(静态检查工具),能提前发现引号缺失、无用变量、[ ] 用法错误等问题,CI 里跑一遍很值。

七、几个易错点

小结

开头 #!/usr/bin/env bash + set -euo pipefail;变量和参数一律加引号;遍历用 "$@";条件用 [[ ]](或兼容性要求高时用 [ ]);调试 bash -x,检查用 shellcheck。

本文相关工具(本地计算,无需上传)

更多使用教程