dsh-bash-native

toolstested: passnpmMIT

Rust-based POSIX bash executor for the Windows platform — gives DSH a native bash with no WSL or MSYS compatibility layer, honors DSH's three-tier permission policy, and provides persistent-terminal tools.

下载量 / Downloads
1,714
依赖体积 / node_modules
62.24 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add dsh-bash-native

Sandbox test results

StageResult
1 install✓
2 list✓
3 mount✓
4 boot—

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

<!-- ═══════════════════════════════════════════════════════════════════════ -->

<div align="center">

🐚 dsh-bash-native

Rust 实现的 Windows 原生 POSIX bash 执行器

给 DSH 的 shell 提供一个真正原生的 bash —— rubash 引擎,不依赖 WSL,也不需要 MSYS 兼容层

<br>

适配三档权限策略 · 后台作业 · 支持持久化终端

<br>

![Listed on dsh-plugin.org](https://dsh-plugin.org/zh/plugins/spookywaste/dsh-bash-native)

![npm downloads](https://www.npmjs.com/package/dsh-bash-native)

![npm](https://www.npmjs.com/package/dsh-bash-native)

![DSH](https://github.com/deepseek-ai/deepseek-harness)

![Powered by rubash](https://github.com/unixwin/rubash)

中文 &nbsp;·&nbsp; [English](README.en.md)

</div>


🐟 为什么需要它

~~避免肥鱼被 cmd 咬~~,也规避了子系统和 MSYS 兼容层的性能开销

0.3.1:引擎由brush更换为rubash,修复多项已知缺陷,提供更好的原生 POSIX 兼容

0.3.3:引擎升级到 rubash 1.5.0——三笔补丁 150-001–150-003,旧补丁随上游合入退役

<p align="center">

<img src="img/example0.jpg" width="240">

</p>

<table align="center">

<thead>

<tr>

<th align="left">方案</th>

<th align="left">命令在哪里执行</th>

<th align="left">每条命令的代价</th>

</tr>

</thead>

<tbody>

<tr>

<td><b>Git for Windows</b></td>

<td>MSYS2 兼容层上的移植 bash,POSIX 语义由运行时模拟</td>

<td>兼容层每次起子 shell 或外部命令都要完整 fork 一个 MSYS2 进程(挂起线程、另起进程、经管道搬运内存),开销随子 shell 启动频率线性放大</td>

</tr>

<tr>

<td><b>WSL</b></td>

<td>命令在 Linux VM 的发行版里执行</td>

<td>每条命令都要经 Windows/Linux 边界往返一次,延迟对高频短命令尤为不利</td>

</tr>

<tr>

<td><b>本插件</b><br><sub>rubash 引擎 + 工具链</sub></td>

<td>纯 Rust 实现的原生二进制,无模拟层、无 VM</td>

<td><code>grep</code>、<code>sed</code>、<code>awk</code> 等来自随包工具链,其余由引擎在进程内处理,没有兼容层或 VM 边界</td>

</tr>

</tbody>

</table>

⚡ 实测:启动与子 shell 的代价

同一台机器(Windows 11 / x64)上的同一组脚本,每项取 5 次最小值,负载只用 shell 内建与一次外部进程,排除工具链差异。

复现:仓库里的 node scripts/bench-engines.mjs。

工作负载 · rubash(本插件) · Git Bash / MSYS2

bash -c :(启动到退出) · 7 ms · 25 ms

echo hi · 6 ms · 26 ms

算术循环 10k 次 · 65 ms · 75 ms

[ ] 判定 20k 次 · 167 ms · 181 ms

命令替换 300 次 · 11 ms · 3052 ms

子 shell 300 次 · 25 ms · 2497 ms

外部进程 20 次(cmd /c exit) · 192 ms · 560 ms

差距来自 fork:MSYS2 每次命令替换与子 shell 都要 fork 一个兼容层进程(约 8–10 ms),rubash 两样都做在进程内(每次约 0.04 ms),300 次就相差 2–3 秒。

🧭 路径不会被“自动替换”

Git Bash / MSYS2 把参数交给原生程序时会猜哪些像路径并改写(/flag → C:/Program Files/Git/flag,于是脚本和 agent 被迫记着 MSYS_NO_PATHCONV=1);连数据位也一起改:用 MSYS 调原生 awk.exe 跑 awk '/x/{print}',程序位到手是 X:/{print},直接语法错误、进错路径。

rubash 不猜:按子进程方言,整条 argv 要么原样交给带 POSIX 层的程序,要么统一翻成 Win32 拼写;随包工具的脚本、模式、程序位永不改写,极大减少了找不到路径的情况。

📦 安装

CLI 安装

以 web profile 为例
dsh plugin --profile web add dsh-bash-native

dsh 网页版 / 桌面版安装

dsh 插件页面 → 右上角 添加插件 → 填入插件名 dsh-bash-native 或仓库地址:
https://github.com/SpookyWaste/dsh-bash-native

重启后,在 Settings → General 里把 Native Bash (Windows) 设为默认 preset(或在会话里切过去)。

持久化终端组件默认关闭,在插件管理中可以打开。见[持久终端组件](#持久终端组件)。

<table>

<tbody>

<tr>

<td><b>平台</b></td>

<td>Windows x64</td>

</tr>

<tr>

<td><b>DSH</b></td>

<td><code>&gt;=0.2.0-rc.2 &lt;0.3.0-0</code>(0.2.0-rc.2 - 0.2.1-rc.5实测)</td>

</tr>

<tr>

<td><b>持久终端组件</b></td>

<td>需要 DSH <code>&gt;=0.2.1-alpha.1</code>才能开启</td>

</tr>

</tbody>

</table>


⚙️ 引擎

引擎是 rubash(unixwin/rubash,Rust 写的 bash 5.3 兼容 shell,MIT),本仓库从源码构建它、按 engine.lock.json 里的 commit 应用三笔补丁,产物 engine/win32-x64/rubash.exe(约 14 MB)随包提交。

兼容 MSYS 的 uname -s 身份(MSYS_NT-…),所以脚本里按 MSYS 分支的逻辑也能成立;并发、取消与作业语义由引擎自己实现,跟 MSYS 运行时无关。

<details>

<summary><b>🧩 补丁清单(点击展开)</b></summary>

<br>

<table>

<thead>

<tr>

<th align="left">补丁</th>

<th align="left">做了什么</th>

</tr>

</thead>

<tbody>

<tr>

<td><code>150-001-cd-into-virtual-roots-with-a-real-directory</code></td>

<td><code>cd</code> 进 <code>/tmp</code> 这类<b>背后有真实目录</b>的虚拟根时,把<b>会话 cwd</b> 也一起移动(1.5.0 里 cwd 是会话状态,不再是进程 cwd):原来只改 <code>PWD</code> 就返回,于是 <code>pwd</code> 报新目录、相对操作数与子进程却还在旧目录。<code>PWD</code>、<code>pwd -P</code>、<code>DIRSTACK</code> 仍然显示 <code>/tmp</code>;<code>/usr</code>、<code>/etc</code>、<code>/bin</code> 没有目录可去,<code>/</code> 没有唯一目标,这四个名字保持只改逻辑状态。</td>

</tr>

<tr>

<td><code>150-002-default-a-unset-locale-family-to-utf-8-on-windows</code></td>

<td>没设 <code>LC_ALL</code>/<code>LC_CTYPE</code>/<code>LANG</code> 时,Windows 上默认按 UTF-8 字符语义:<code>${#中文}</code> 是 2、<code>[[:alpha:]]</code> 认 CJK、<code>${v:0:2}</code> 切两个字符。1.5.0 把空的 locale 族解释成 C locale(按字节),这条把它改回 1.4.3 的默认;显式写 <code>LC_ALL=C</code> 仍然按字节。</td>

</tr>

<tr>

<td><code>150-003-identity-tools-answer-without-a-path-program</code></td>

<td><code>PATH</code> 上没有 <code>uname</code>/<code>arch</code> 程序时仍由引擎作答(MSYS 人设):1.5.0 的进程内仿真要先解析到程序,否则让位给一次必然失败的 spawn。可解析的一侧不变——<code>PATH</code> 上的同名脚本仍然会运行。</td>

</tr>

</tbody>

</table>

</details>

💡 每次解析都按 lock 里的 sha256 校验产物,并按盖章跳过重复校验:产物的 size 与 mtime 记进 %LOCALAPPDATA%\dsh-bash-native\verified\,没变就不再读那 14 MB(verifyArtifacts: 'always' 可恢复每次都哈希)。

🔧 实现

  • 注册 ctx.shell:ShellExecutor 的 Service Provider,构建在 @deepseek-ai/dsh-bash-local 之上,每条命令交给解析到的 rubash 引擎;引擎与工具链都随包分发,并在解析时按 lock 与 manifest 校验。
  • 服从 DSH 的三档文件策略(read-only / workspace-write / danger-full-access):受限档位把引擎 argv 交给 ctx.sandbox,不限档位直接 spawn 并如实报告档位。
  • 后台作业经 ctx.jobs 汇报,超出内存上限的输出落到 spill 文件、路径随结果返回;echo、cat、sort 等空 PATH 也能跑,因为随包工具链先于宿主 PATH。
  • Web 面用自带的 agent preset 挂载,agent 面用 overlay 显式启用;它不替换宿主层的 ctx.shell,因此其他 preset 的 pwsh 工具不受影响。

🎛 两个预设

[cordis.patch.yml](cordis.patch.yml) 只有一行注册器(dsh-bash-native/presets),

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::10,最后更新 2026-11-04

Links

GitHub · Homepage · npm

Same category