set -x 能立刻看到执行过程,因为它开启shell跟踪模式,将每条实际执行的命令(含展开后的参数)在运行前打印到stderr,输出前缀为+,仅对当前shell生效且不显示注释或空行。

set -x 为什么能立刻看到执行过程
因为 set -x 会开启 shell 的“跟踪模式”,每条实际执行的命令(展开后、带参数值的)都会在运行前自动打印到 stderr。它不分析逻辑,只忠实地回显——所以你看到的,就是 shell 真正拿到并执行的东西。
常见错误现象:脚本看似没输出、卡住或跳过某段逻辑,但加了 set -x 后发现某行根本没执行,或者执行的是 cp file.txt /tmp/ 而不是你以为的 cp "$SRC" "$DST"——说明变量为空或未导出。
- 只对当前 shell 生效,子 shell(如管道中的
grep、$(cmd))默认不继承,需显式写set -x进去 - 输出前缀是
+,比如+ echo hello,可配合2>&1 | grep "^+"快速过滤 - 不要在生产环境长期开启,尤其含敏感变量(如密码、token)的脚本,
set -x会直接打出来
如何精准控制调试范围,避免满屏噪音
全局加 set -x 容易被初始化、环境检测等无关输出淹没。真正要查的,往往只是某段逻辑分支或函数内部。
使用场景:函数调用链深、条件分支多、只怀疑某几行有问题。
- 在函数开头加
set -x,结尾加set +x(+ 表示关闭),例如:my_func() { set -x cp "$1" "/tmp/" [ -f "/tmp/$(basename "$1")" ] set +x } - 用
set -o xtrace和set +o xtrace效果相同,但更显式;set -x更常用 - 临时调试某一行?前面加
set -x;,后面加分号接set +x,比如:set -x; ls -l "$DIR"; set +x
为什么有时 set -x 没输出,或输出和预期不符
不是 set -x 失效,而是 shell 执行路径根本没走到那里——比如条件判断失败、函数未被调用、或者脚本被 exit 中断了。
典型表现:set -x 加在 if 块里,但什么都没打印;或只看到部分命令,后续消失。
- 检查是否提前
exit或遇到set -e导致的非零退出而终止执行 - 确认变量是否为空导致条件跳过,例如
[ -n "$VAR" ] && { set -x; do_something; set +x; },若$VAR为空,整个块都不会执行 -
set -x输出走 stderr,如果脚本重定向了 stderr(如2>/dev/null),就看不到任何跟踪信息 - 某些 shell(如 dash)不支持
set -x的某些变体,优先用bash -x script.sh替代
bash -x script.sh 和脚本内 set -x 有什么区别
本质一样,都是启用 xtrace,但触发时机和作用域不同:前者是启动时全局开启,后者是运行中动态开关。
性能与兼容性影响:无实质差异,但启动参数方式更可靠,尤其当脚本本身有语法错误、或依赖特定 shebang 时。
-
bash -x script.sh会忽略脚本第一行的#!/bin/sh,强制用 bash 解释,适合调试 bash 特有语法(如[[、数组) -
sh -x script.sh更贴近真实运行环境(如果脚本声明为#!/bin/sh),但不支持 bash 扩展 - 如果脚本用了
exec替换自身进程(如exec python3 ...),set -x在 exec 后失效,而bash -x只能跟踪到 exec 前
最常被忽略的一点:set -x 不会显示注释、空行、或语法错误本身——它只跟踪成功解析并准备执行的命令。想定位语法错误,得靠 bash -n script.sh 先做语法检查。










