返回 Bug 清单
BUG-0217project-12中已修复deploy-script
错误捕获钩子用 trap ERR + ${BASH_COMMAND} —— 记录到的是 trap 自身的命令
发现:2026-10-01验证:2026-10-27置信度:97%
症状
一个用于记录「哪条命令失败了」的 bash 钩子,产物里大量出现自指记录:记录的命令内容是 local __cmd="${BASH_COMMAND:-unknown}"、__cmd="${BASH_COMMAND:-unknown}" 等 —— 那正是钩子自身的语句。实测 5 条记录里 3 条是这种噪声(60%)。
根因
两个缺陷叠加:
① ${BASH_COMMAND} 在 ERR trap 【内部】求值时,返回的是【当前正在执行的命令】—— 也就是 trap 函数体里的语句,而不是触发 trap 的那条失败命令;
② `DBUG_IN_HOOK=1 __dbug_write …` 这种「前缀赋值 + 命令」的形式, 拦不住 __dbug_on_err 自身内部语句失败时【再次进入 trap】(那时变量还没设上)。
修复方案
改用 PROMPT_COMMAND(在命令执行完、显示提示符前运行一次的函数):
· $? 语义正确(就是上一条命令的退出码)
· 用 history 1 取最后执行的命令,不涉及 trap 内部命令
· 它不是信号陷阱,天然不会递归
· 与 PowerShell 的 prompt 函数同构 ⇒ 两侧行为一致
另需注意:
· history 行形如 " 123 cmd",解析要用锚定正则 ^[[:space:]]*[0-9]+[[:space:]]+(.*)$(用 ${var#*[0-9]} 对多位序号与 " 8 cmd" 会解析错误);
· 引用环境变量一律用 ${VAR:-} —— 否则用户 shell 开了 set -u 时钩子会报 "VAR: unbound variable",违反其「绝不影响主 shell」的承诺;
· 挂载要幂等,并保留既有的 PROMPT_COMMAND 内容。
检测命令
grep -cE '__dbug|BASH_COMMAND' ~/.dbug/errors.jsonl # 自指记录数修复命令
# 用 PROMPT_COMMAND 替代 trap ERR
__dbug_on_prompt() {
local __ec=$?
[ "$__ec" -eq 0 ] && return 0
[ -n "${DBUG_HOOK_OFF:-}" ] && return 0
local __raw; __raw="$(HISTTIMEFORMAT= builtin history 1 2>/dev/null)"
if [[ "$__raw" =~ ^[[:space:]]*[0-9]+[[:space:]]+(.*)$ ]]; then __cmd="${BASH_REMATCH[1]}"; fi
...
}
PROMPT_COMMAND="__dbug_on_prompt${PROMPT_COMMAND:+;$PROMPT_COMMAND}"错误签名
{"command":"local __cmd=\"${BASH_COMMAND:-unknown}\""} —— 记录的"失败命令"是钩子内部代码技术信息
来源项目
project-12
标签
bash, trap, err-trap, prompt-command, hook...