Execution model: three tiers, zero forks

POSIX fork() has no equivalent on Win32. MSYS2/Cygwin's answer is to fabricate it at the syscall layer — expensive, fragile, and famous for its quirks. niubash's engine (rubash) takes a different road: replicate fork's semantics, not its mechanism. The result: subshells and command substitution at zero process-creation cost, while everything a script can observe — exit codes, fd inheritance, shared offsets, signal disposition — matches GNU Bash.

The three-tier model

TierMechanismWhich face of fork it covers
1. In-process subshells ( list ) and $( ) never create a process: ShellState::clone copies variables, aliases, functions, traps and history; the subshell ends and the copy is discarded. fork's copied "memory face".
2. A real-handle fd table Slots hold native Windows HANDLEs; handles duplicated via DuplicateHandle share the same kernel file object — hence shared file offsets, exactly POSIX "dup shares the open file description" (proven with a POC before landing). fork_table() copies the whole table handle by handle. fork copies the fd table but not the file object.
3. Real processes only at boundaries External commands and pipeline members start via CreateProcess + os_pipe; background jobs and coprocs each hold a real process, job control builds on Job Objects, SIGCONT goes through ResumeThread. Where fork is genuinely unavoidable: the process boundary.

In other words: what can avoid creating a process (subshells, command substitution) never creates one; what must create a process (external commands, pipelines, background jobs) takes Win32's native path directly. No "simulated POSIX" layer sits in between.

62 real builtins + 12 inlined coreutils + pipeline-inline arms

Command words dispatch in three tiers. 62 real builtins execute in-process (all 61 of GNU Bash 5.3's builtins covered, none missing, plus an in-process env — coreutils semantics, sorted output, -0 support). There are also hidden fast-paths (sleep/dirname/basename/uname/arch): simple argument forms run in-process, complex forms fall back to the external command, and introspection (type/command -v/enable) reports them as external commands — same as GNU Bash reports.

In-process tierRosterNotes
Inlined file commands (12) pwd printf mkdir touch chmod cp rm rmdir cat sed mkfifo tty High-frequency file commands execute in-process inside the engine (aligned to GNU coreutils stdout/rc; complex forms with flags fall back to the external command).
Pipeline-inline arms true : false echo printf trap head cat sed grep wc tr Matched by the command's position in the pipeline: a hit runs in-process; only refused forms (e.g. grep regex metacharacters) fall back to the external binary.

Combined, a pipeline like echo | cat is entirely zero-process. The roster is not a documentation slogan: the builtin whitelist and the fast-path list are guarded by cargo-test documentation-sync tests — change either side of code or docs without the other and the build fails.

中文原文 · Chinese original

命令词按三层分发。62 个真内建进程内执行(GNU Bash 5.3 的 61 个内建全覆盖、无缺失,外加进程内 env—— coreutils 语义、排序输出、支持 -0)。另有隐藏 fast-path (sleep/dirname/basename/uname/arch): 简单参数形态进程内执行,复杂形态回退外部命令,而 introspection (type/command -v/enable)报告为 外部命令——与 GNU Bash 的报告一致。

组合起来,echo | cat 这样的管道一整个零进程。 名单不是文档口号:内建白名单与 fast-path 清单由 cargo test 的 文档同步测试守护——代码与文档任何一侧变动,另一侧不改则构建失败。

Observable behavior: zero difference, proven

"Implemented differently" is not a euphemism for "behaves differently". The observable surface of this model — exit code propagation, fd inheritance and shared offsets, signal disposition — is exactly what GNU's 83 upstream test corpora cover: 83/83 passing, 82 suites byte-identical (see the compatibility overview). As corroborating evidence, the engine also runs the core loop of the bashdb debugger end-to-end (list/step/next/where/continue/quit) and git's own test framework t/test-lib.sh — both extremely sensitive to execution-model details.

For the performance payoff of this design (subshells, command substitution, background jobs) and the honest parity floor of external processes, see the performance profile.