Skip to content

fix(terminal): 修复 PROMPT_COMMAND 钩子在子 shell 报「未找到命令」(#217) - #229

Merged
feigeCode merged 2 commits into
mainfrom
fix/bash-prompt-command-not-found-217
Sep 18, 2026
Merged

feigeCode merged 2 commits into
mainfrom
fix/bash-prompt-command-not-found-217

Conversation

@feigeCode

Copy link
Copy Markdown
Owner

现象

部分服务器上执行命令时会额外输出一行 bash: __onetcli_precmd_bash:未找到命令#217)。

根因

crates/terminal/src/shell_integration.sh 的 bash 分支把 PROMPT_COMMAND 注册成裸函数名 __onetcli_precmd_bash

PROMPT_COMMAND 是 shell 局部机制,但它的可以被环境导出并被之后的 shell(sutmuxexec bash、嵌套 ssh 等链路)继承。继承它的 shell 里并没有本文件定义的函数(函数不随环境走),于是 bash 在求值 PROMPT_COMMAND 时每个提示符都报一次「未找到命令」。

同一个 shell 内不可能出现这种不一致(PROMPT_COMMAND 赋值在函数定义之后),所以报错必然来自继承了该变量的另一个 bash 进程;这也解释了为什么只有部分服务器复现。

顺带排除一条看似相关的路径:set -a(allexport)会把函数定义一起导出(BASH_FUNC_*),那种环境下子 shell 反而能拿到函数、不会报错——所以只有判断函数是否存在才是通用兜底,不能依赖某一种导出方式。

修改

  • 钩子改为自带存在性判断的命令串:

    __ONETCLI_EXIT=$?; command -v __onetcli_precmd_bash >/dev/null 2>&1 && __onetcli_precmd_bash "$__ONETCLI_EXIT"

    command -v 是内建命令,不产生 fork;函数缺失时静默跳过。

  • 退出码改为在钩子里先取好再显式传给函数:钩子里的 command -v 会覆盖 $?,若仍让函数自己去读 $?,上报的 exit code 会恒为 0、133;D 失效。

  • 新增两个回归测试(先红后绿):继承钩子但没有函数的 shell 必须静默;主 shell 的退出码必须仍上报。

  • 设计文档记录该约束,避免以后被简化回裸函数名。

验证

  • cargo test -p terminal:503 项 lib 测试通过
  • cargo clippy -p terminal --all-targets:改动文件零告警
  • 真实交互式 bash 对比复现(export PROMPT_COMMAND 场景):修复前子 shell 输出 2 行 bash: __onetcli_precmd_bash: command not found,修复后 0 行
  • 主 shell 集成未退化:false133;D;1true133;D;0

风险 / 后续

  • 修复随运行时注入下发,服务器上无需任何清理。
  • 若现场仍复现,在报错的那个 shell 里执行 echo "$PROMPT_COMMAND"; type -t __onetcli_precmd_bash,可确认它的 PROMPT_COMMAND 是从哪条链路继承来的。
  • 目前只有自动化测试覆盖,真机复现仍需问题服务器(当前不可达)。

Closes #217

feigeCode and others added 2 commits September 18, 2026 17:57
bash 分支把 PROMPT_COMMAND 注册成裸函数名。PROMPT_COMMAND 是 shell 局部机制,
但它的值可能被环境导出并被后续 shell(su、tmux、exec bash、嵌套 ssh)继承,
而那些 shell 里没有本文件定义的函数,于是每个提示符都多输出一行
「bash: __onetcli_precmd_bash:未找到命令」,即 issue #217 的现象。

- 钩子改为自带存在性判断的命令串:`command -v` 是内建命令,函数缺失时静默跳过、
  不产生 fork,也不受继承链路影响;
- 退出码必须在钩子里先取好再显式传给函数:钩子里的 `command -v` 会覆盖 `$?`,
  若仍让函数自己去读 `$?`,上报的 exit code 会恒为 0、`133;D` 失效;
- 补两个回归测试:继承钩子但没有函数的 shell 必须静默、主 shell 退出码必须仍上报;
- 设计文档记录该约束,避免以后被简化回裸函数名。

验证:`cargo test -p terminal`(503 lib 测试通过)、
`cargo clippy -p terminal --all-targets`(改动文件零告警);另在真实交互式 bash 中
对比复现:修复前子 shell 输出 2 行 command not found,修复后 0 行,
主 shell 的 `133;D` 退出码上报仍为 `false`→1、`true`→0。
@feigeCode
feigeCode merged commit cc196e5 into main Sep 18, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: 执行命令总是额外输出【bash: __onetcli_precmd_bash:未找到命令】

1 participant