最实用方式是用 Bash 内置变量 $LINENO 和 ${BASH_SOURCE[0]} 定义 debug 函数自动输出文件名与行号,支持多文件 source 场景;配合 set -x 与 PS4 可全自动追踪,再通过 DEBUG 开关和重定向实现灵活调试。

在 Linux 复杂脚本中输出带行号的调试信息,核心是让每条日志自动附带当前执行位置(文件名 + 行号),避免手动写死或反复修改。最实用、轻量且兼容性强的方式是利用 Bash 内置的特殊变量和 printf 或 echo 组合实现。
用 $LINENO 和 $0 自动标记行号与脚本名
Bash 提供 $LINENO(当前行号)和 $0(脚本路径)两个变量,无需额外工具即可实时获取上下文。适合绝大多数调试场景:
- 直接在关键逻辑前后插入:
echo "DEBUG [$0:$LINENO] 正在检查配置文件" - 为避免重复书写,可定义调试函数:
debug() { printf "DEBUG [%s:%d] %s\n" "$0" "$LINENO" "$*"; }
然后调用debug "参数校验完成,count=$count" - 注意:
$LINENO在函数内部显示的是调用该函数那一行的行号(非函数定义处),这对定位调用点反而更直观
结合 BASH_SOURCE 提升多文件脚本的可读性
当脚本拆分为多个 source 文件(如 当脚本拆分为多个 source 文件(如 lib.sh、main.sh),仅用 会始终显示主脚本名。此时改用 lib.sh、main.sh),仅用 $0 会始终显示主脚本名。此时改用 ${BASH_SOURCE[0]} 可准确反映当前被 source 的文件:${BASH_SOURCE[0]} 可准确反映当前被 source 的文件:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
- 定义增强版 debug:
debug() { printf "DEBUG [%s:%d] %s\n" "${BASH_SOURCE[0]}" "$LINENO" "$*"; } - 若需显示调用栈深度(比如嵌套 source),可加
${#BASH_SOURCE[@]}辅助判断,但通常不必要 - 该方式在
source lib.sh后,lib.sh 中的 debug 输出自然显示 lib.sh 的行号
用 set -x 配合 PS4 实现全自动行号追踪
对整段逻辑快速“透视”,推荐启用 Bash 跟踪模式。它自动打印每条执行命令,并可通过 PS4 自定义前缀格式:
- 启用方式:
set -x(开启),set +x(关闭) - 设置带行号的提示符:
PS4='+ [${0##*/}:${LINENO}] ',其中${0##*/}提取脚本名(去掉路径) - 效果示例:
+ [deploy.sh:42] if [[ -f /tmp/lock ]]; then - 优点:零侵入,适合临时排查流程卡点;缺点:输出较冗长,不适合长期开启或生产环境
进阶:按条件开关调试输出
避免调试语句污染正式运行,建议封装开关机制:
- 启动时支持
-d参数:[[ "$1" == "-d" ]] && DEBUG=1 - debug 函数内加判断:
[[ $DEBUG ]] && printf "DEBUG [%s:%d] %s\n" "${BASH_SOURCE[0]}" "$LINENO" "$*" - 还可将输出重定向到文件:
debug() { [[ $DEBUG ]] && printf ... >> /tmp/script-debug.log; }










