Repository navigation
极简模式中 Agent Bash 工具遇命令裸 ! 卡住:dsh 持久 shell 的 history expansion 中止包装命令 #6768
ErickYu-code
started this conversation in
General
Replies: 1 comment
|
我也遇到的相同的问题 |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
现象
极简模式中 Agent 的 Bash 工具执行任何包含**裸
!(未转义的感叹号)**的命令时会卡住,命令通常没有真正执行。手动在 zsh / 终端里执行同样的命令则立即成功。首次发现于以下 Swift 单行命令:
手动终端正常输出:
{"url":"https:\/\/media.example.com\/a.heic"}Agent Bash 工具内相同命令一直无响应,看起来像进程死锁。
影响
!的命令都可能无法执行。echo 'hi!'同样卡住。URL(...)!、String(...)!)会触发,因此这类命令无法作为单行
swift -e交给 Agent 执行。sudo、网络、URL、代码签名均无关;换用sudo也不会恢复。复现
在 Agent Bash 工具中:
以下命令会卡住:
或
以下命令正常,可对照证明问题来自裸
!:在同一个 Agent 持久 shell 中先执行
set +H,再执行原始命令,立即成功:输出:
{"url":"https:\/\/media.example.com\/a.heic"}根因
运行环境
Agent Bash 工具由 dsh 的持久 PTY 提供,底层 shell 为:
相关环境变量与选项:
dsh 的命令包装
@deepseek-ai/dsh-tool-bash-persistent为了识别输出与退出码,会把用户命令包装成类似:其中
quoteForBash(value)使用 Bash ANSI-C 引号$'...',并在value中替换:\→\\'→\'\r→\r\n→\n但没有处理裸
!。Bash history expansion 中止包装行
持久 shell 是 interactive Bash,
histexpand默认开启。Bash 在解析整条包装命令前先做历史展开,此时会看到用户命令中的
!,例如原始命令echo 'hi!'经 dsh 转义单引号后,包装文本里出现类似:
Bash 尝试把
!\'当历史事件名查找,直接报错:整行包装命令因此不会执行,
START和END标记都不会输出。dsh 收不到结束标记,就一直等待,直到约 30 秒超时,再由工具层统一报错/重置 shell。这就是“卡住”的来源。
为什么手动终端成功
手动终端是 zsh;
!位于单引号内时既不触发 zsh history expansion,也没有 dsh 的
$'...'包装层。因此 shell 收到的是原始命令,Swift 能正常编译执行。证据
在 Agent Bash 工具内,包装逻辑与 Bash 行为的对照验证:
用与 dsh 相同的包装形式在
/bin/bash --noprofile --norc -i中复现,确实出现:且后续
__DSH_PERSISTENT_BASH_END_...标记不会输出。规避方案
1. 执行命令前关闭 histexpand(临时)
在同一个 Agent 持久 shell 中先单独执行:
set +H之后包含裸
!的命令即可原样执行。注意set +H必须单独先执行,不能和含
!的命令写在同一条包装命令里,因为 history expansion 发生在整行解析阶段。如果 shell 被 dsh 重置,需要重新执行。
2. 避免命令文本中出现裸
!Swift 强制解包改为
guard let/if let:Shell 层使用
printf的八进制转义生成感叹号:也可以使用无引号
echo hi\!(注意不能写成echo 'hi\!',否则单引号会保留反斜杠)。3. 源码写入文件再执行
对于必须保留原代码
!的场景,可把 Swift 源码先写入文件(例如通过不含!的base64 传输),再执行
swift /tmp/test.swift,避免命令文本经过 shell 的 history expansion。建议修复(dsh 上游)
quoteForBash中把!编码为 ANSI-C 八进制转义\041,再放进$'...'。这样发送给 PTY 的包装文本里没有裸
!,Bash history expansion 不会触发,而
eval会还原出真正的!。需要保证替换顺序在反斜杠转义之后,不能二次转义。set +H关闭历史展开。不能仅在每条包装命令前加
set +H,因为同一行内的!仍在 history expansion 阶段被扫描。wrapCommand+quoteForBash后,echo 'hi!'、echo "a!b"、强制解包 Swift 单行命令等都必须正常返回输出和退出码,且不超时。验收标准
echo 'hi!'不再超时,输出hi!和正确退出码。URL(...)!和String(...)!的原始swift -e单行命令成功。set +H作为 workaround。!的命令行为、输出解析、退出码传递无回归。All reactions