Experiment 03 / practical shell work
Start a shell.
Then put it to work.
Startup, explicit configuration, substantial native logic, process pipelines and mixed filesystem tasks in Bash, Zsh, Fish, Nushell and Nift. Different architectures, checked outputs and every observation retained.
Stages explain the model; individual stage durations were not measured. Only the total startup boundary is timed.
Series 20261015-v4120-final-c14d068 · Nift 4.12.0 final candidate · frozen source revision. Current figures use final audited observations. Earlier reports retain their own dated series; samples are not pooled.
Startup / distributions
A median does not show every stall.
| Shell | Exit ms | Trivial ms | Prompt ms | Prompt p95 | Prompt p99 |
|---|---|---|---|---|---|
| bash | 1.712 | 1.620 | 2.089 | 2.678 | 2.979 |
| zsh | 2.186 | 2.086 | 2.844 | 3.539 | 3.830 |
| fish | 2.364 | 2.228 | 19.347 | 24.007 | 26.893 |
| nu | 13.638 | 13.569 | 17.365 | 19.745 | 20.174 |
| nift | 2.425 | 2.202 | 1.986 | 2.483 | 2.689 |
Bash’s bare prompt median was 2.089 ms and Zsh’s was 2.844 ms. Their p99 values were 2.979 and 3.830 ms; Nift’s was 2.689 ms. Tails remain visible even where medians are small.
Download the SVG figure · PNG figure.
Exit/trivial use C-supervised non-interactive command evaluation. Prompt startup uses a real controlling PTY, excludes Python/bridge launch but includes PTY forwarding and minimal xterm query handling, then validates RC state. Those boundaries differ; subtracting them would not recover RC cost.
Configuration is a variable
Bare → Empty → Light → Moderate
Light/moderate also prepend one PATH entry and perform a HOME-existence conditional. A post-prompt oracle validates representative environment, function and conditional state. No aliases or plugin managers are forced onto shells without equivalent facilities.
| Shell | Bare ms | Empty ms | Light ms | Moderate ms |
|---|---|---|---|---|
| bash | 2.089 | 3.693 | 3.833 | 4.035 |
| zsh | 2.844 | 27.532 | 27.848 | 27.812 |
| fish | 19.347 | 40.089 | 41.109 | 38.524 |
| nu | 17.365 | 20.642 | 21.037 | 21.051 |
| nift | 1.986 | 1.974 | 2.350 | 2.770 |
| Shell | Bare ms | Empty ms | Light ms | Moderate ms |
|---|---|---|---|---|
| bash | 2.081 | 3.703 | 3.865 | 4.080 |
| zsh | 2.912 | 538.7 | 540.5 | 541.3 |
| fish | 20.046 | 72.752 | 68.965 | 68.024 |
| nu | 17.503 | 20.515 | 20.576 | 21.171 |
| nift | 1.999 | 2.042 | 2.324 | 2.763 |
Login matrix
| Shell | Bare ms | Empty ms | Light ms | Moderate ms |
|---|---|---|---|---|
| bash | 2.049 | 18.587 | 18.676 | 18.822 |
| zsh | 2.753 | 27.554 | 27.716 | 27.660 |
| fish | 20.648 | 39.898 | 39.687 | 40.014 |
| nu | 17.964 | 20.837 | 20.859 | 21.320 |
Fresh configured Zsh medians were 538.7 ms for empty user files and 541.3 ms for moderate files. Ubuntu’s normal system completion setup rebuilds per fresh HOME; the normal-path matrix includes that work.
Bare means no user config. Zsh still reads compiled system zshenv. Normal/login paths retain distro-wide configuration. Nift uses isolated HOME because there is no no-RC option; Nu keeps its standard library. Direct startup measurements are never derived by subtracting RC time. Fresh application directories reset config/cache/history state without flushing OS caches.
Orchestration & native work
The shell has work to do.
| Workload | bash | zsh | fish | nu | nift |
|---|---|---|---|---|---|
| native-sum | 5.099 | 3.235 | 107.6 | 14.410 | 3.041 |
| function-string | 1.723 | 2.191 | 2.695 | 14.435 | 2.256 |
| external-100 | 88.309 | 99.042 | 74.404 | 94.050 | 92.969 |
| short-pipeline | 4.335 | 4.787 | 4.470 | 16.060 | 5.098 |
| command-capture | 3.120 | 3.556 | 3.814 | 14.916 | 3.514 |
| file-roundtrip | 4.022 | 4.453 | 4.638 | 16.668 | 4.910 |
Sum uses assignments, arithmetic, conditions and loops. Function-string defines a callable and changes case/replaces characters. External-100 runs the same absolute /usr/bin/true 100 times. Pipeline uses identical printf/tr executables; Nift uses structured run()/cmd().pipe() capture. The file row executes identical /usr/bin/printf and /usr/bin/cat helpers in all five shells; writing uses POSIX redirection, Nu save or Nift’s file API after structured capture. It measures that mixed orchestration/I/O workflow, not pure native file-read throughput. Equivalent output does not imply identical internal architecture.
Bash’s trivial invocation was 1.620 ms versus Nift’s 2.202 ms. Fish’s external-100 median was 74.404 ms versus Nift’s 92.969 ms. These rows show why prompt latency alone cannot rank shell performance.
| Shell | Trivial RSS MiB |
|---|---|
| bash | 3.375 |
| zsh | 3.625 |
| fish | 5.375 |
| nu | 24.875 |
| nift | 5.875 |
PTY RSS is omitted because prompt timing stops before oracle/teardown accounting. Parallel job-control and personal/default-dotfile distributions remain outside this series. The additive workload layer below covers longer pipelines, traversal and practical tasks.
Measurement boundaries
Different architectures. Equivalent tasks.
Runtime-native cases execute shell arithmetic, functions and strings. Orchestration cases coordinate the same absolute GNU executables. End-to-end filesystem cases allow each shell’s normal APIs: Bash/Zsh/Fish use batching/redirection; Nushell and Nift use native operations. Direct GNU xargs baselines exclude shell launch. These are user-task comparisons, not five equivalent filesystem engines. Added tasks run as bare, non-interactive invocations: elapsed time includes launch and program work, while fixture setup and complete validation remain outside timing.
100,000 targets + 20,000 keepers
Selected files. Nothing else.
Deterministic target and keeper names are interleaved. Flat cases share one directory; the tree variant distributes both sets over 100 directories. Removing a target-only parent or the entire workspace fails validation. Selected deletion reads an exact manifest; batching avoids ARG_MAX. Nift/Nushell have native selected deletion; Bash/Zsh/Fish have no native deletion result, and their end-to-end GNU rm results remain visible.
Empty creation measures inode creation; small creation writes 128 bytes per target. Nift’s file save uses temporary-file replacement, while other implementations have different write paths. We disclose that extra atomic-save work rather than claiming equivalent internals. All target bytes, all keeper bytes, keeper mode/mtime/inode, counts and unexpected files are checked outside timing.
Native selected-delete subset: the Nift and Nushell observations use their runtime filesystem APIs. Traditional shells have no native deletion primitive; their end-to-end timings below use batched GNU rm. The native subset reuses those exact checked observations, rather than timing an artificial second implementation.
| Native deletion | Bash | Zsh | Fish | Nushell s | Nift s |
|---|---|---|---|---|---|
| 100k flat | — | — | — | 6.760 | 2.967 |
| 100k tree | — | — | — | 7.306 | 2.848 |
filesystem
Filesystem operations
| Task size | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Elapsed time vs sizeLogarithmic task-size axis; lines connect measured points. | |||||
| 1000 | 0.034 | 0.052 | 0.051 | 0.050 | 0.038 |
| 10000 | 0.331 | 0.516 | 0.496 | 0.358 | 0.368 |
| 100000 | 3.499 | 5.261 | 5.128 | 3.600 | 3.885 |
| Task size | Bash | Zsh | Fish | Nushell | Nift | GNU baseline |
|---|---|---|---|---|---|---|
| Elapsed time vs sizeLogarithmic task-size axis; lines connect measured points. | ||||||
| 1000 | 0.023 | 0.025 | 0.025 | 0.065 | 0.025 | 0.022 |
| 10000 | 0.205 | 0.204 | 0.202 | 0.536 | 0.240 | 0.201 |
| 100000 | 2.218 | 2.648 | 2.670 | 6.760 | 2.967 | 2.279 |
create-empty-1000
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| p95 | 0.037 | 0.055 | 0.055 | 0.056 | 0.042 |
| Minimum | 0.033 | 0.050 | 0.049 | 0.046 | 0.036 |
| Maximum | 0.038 | 0.055 | 0.056 | 0.058 | 0.042 |
| System | Implementation |
|---|---|
| Bash | shell redirection |
| Zsh | shell redirection |
| Fish | shell redirection |
| Nushell | native filesystem API |
| Nift | native filesystem API |
Bash
while IFS= read -r p || [ -n "$p" ]; do : > "$p"; done < targets.txt; echo OK
Zsh
while IFS= read -r p || [ -n "$p" ]; do : > "$p"; done < targets.txt; echo OK
Fish
while read -l p; printf %s '' > "$p"; end < targets.txt; echo OK
Nushell
for p in (open --raw targets.txt | lines) { "" | save --raw $p }; print OKNift
paths := open("targets.txt").trim().split("\n"); for(p : paths) { touch(p) }; print("OK")Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
delete-selected-1000
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift | GNU baseline |
|---|---|---|---|---|---|---|
| p95 | 0.025 | 0.026 | 0.030 | 0.068 | 0.027 | 0.024 |
| Minimum | 0.022 | 0.023 | 0.023 | 0.061 | 0.025 | 0.021 |
| Maximum | 0.025 | 0.026 | 0.033 | 0.069 | 0.028 | 0.024 |
| System | Implementation |
|---|---|
| Bash | batched GNU utilities |
| Zsh | batched GNU utilities |
| Fish | batched GNU utilities |
| Nushell | native filesystem API |
| Nift | native filesystem API |
| GNU baseline | direct GNU xargs + /usr/bin/rm |
Bash
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Zsh
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Fish
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Nushell
let paths = (open --raw targets.txt | lines); rm ...$paths; print OK
Nift
paths := open("targets.txt").trim().split("\n"); remove(paths); print("OK")GNU baseline
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --
Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
create-empty-10000
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| p95 | 0.358 | 0.553 | 0.524 | 0.393 | 0.421 |
| Minimum | 0.317 | 0.507 | 0.489 | 0.347 | 0.344 |
| Maximum | 0.370 | 0.574 | 0.526 | 0.400 | 0.429 |
| System | Implementation |
|---|---|
| Bash | shell redirection |
| Zsh | shell redirection |
| Fish | shell redirection |
| Nushell | native filesystem API |
| Nift | native filesystem API |
Bash
while IFS= read -r p || [ -n "$p" ]; do : > "$p"; done < targets.txt; echo OK
Zsh
while IFS= read -r p || [ -n "$p" ]; do : > "$p"; done < targets.txt; echo OK
Fish
while read -l p; printf %s '' > "$p"; end < targets.txt; echo OK
Nushell
for p in (open --raw targets.txt | lines) { "" | save --raw $p }; print OKNift
paths := open("targets.txt").trim().split("\n"); for(p : paths) { touch(p) }; print("OK")Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
delete-selected-10000
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift | GNU baseline |
|---|---|---|---|---|---|---|
| p95 | 0.208 | 0.233 | 0.212 | 0.566 | 0.268 | 0.217 |
| Minimum | 0.197 | 0.198 | 0.195 | 0.521 | 0.233 | 0.194 |
| Maximum | 0.209 | 0.241 | 0.212 | 0.570 | 0.271 | 0.219 |
| System | Implementation |
|---|---|
| Bash | batched GNU utilities |
| Zsh | batched GNU utilities |
| Fish | batched GNU utilities |
| Nushell | native filesystem API |
| Nift | native filesystem API |
| GNU baseline | direct GNU xargs + /usr/bin/rm |
Bash
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Zsh
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Fish
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Nushell
let paths = (open --raw targets.txt | lines); rm ...$paths; print OK
Nift
paths := open("targets.txt").trim().split("\n"); remove(paths); print("OK")GNU baseline
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --
Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
create-empty-100000
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| p95 | 3.635 | 5.392 | 5.138 | 3.676 | 3.889 |
| Minimum | 3.359 | 5.173 | 5.082 | 3.577 | 3.772 |
| Maximum | 3.645 | 5.411 | 5.138 | 3.685 | 3.889 |
| System | Implementation |
|---|---|
| Bash | shell redirection |
| Zsh | shell redirection |
| Fish | shell redirection |
| Nushell | native filesystem API |
| Nift | native filesystem API |
Bash
while IFS= read -r p || [ -n "$p" ]; do : > "$p"; done < targets.txt; echo OK
Zsh
while IFS= read -r p || [ -n "$p" ]; do : > "$p"; done < targets.txt; echo OK
Fish
while read -l p; printf %s '' > "$p"; end < targets.txt; echo OK
Nushell
for p in (open --raw targets.txt | lines) { "" | save --raw $p }; print OKNift
paths := open("targets.txt").trim().split("\n"); for(p : paths) { touch(p) }; print("OK")Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
delete-selected-100000
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift | GNU baseline |
|---|---|---|---|---|---|---|
| p95 | 2.525 | 2.737 | 2.771 | 7.030 | 3.124 | 2.652 |
| Minimum | 2.095 | 2.157 | 2.506 | 6.502 | 2.723 | 2.119 |
| Maximum | 2.532 | 2.752 | 2.782 | 7.056 | 3.132 | 2.741 |
| System | Implementation |
|---|---|
| Bash | batched GNU utilities |
| Zsh | batched GNU utilities |
| Fish | batched GNU utilities |
| Nushell | native filesystem API |
| Nift | native filesystem API |
| GNU baseline | direct GNU xargs + /usr/bin/rm |
Bash
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Zsh
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Fish
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Nushell
let paths = (open --raw targets.txt | lines); rm ...$paths; print OK
Nift
paths := open("targets.txt").trim().split("\n"); remove(paths); print("OK")GNU baseline
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --
Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
create-small-100000
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–11.689 s | |||||
| Median s | 4.905 | 6.763 | 8.107 | 4.769 | 10.824 |
| p95 s | 4.977 | 6.882 | 8.235 | 4.994 | 10.925 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | shell redirection |
| Zsh | shell redirection |
| Fish | shell redirection |
| Nushell | native filesystem API |
| Nift | native filesystem API |
Bash
while IFS= read -r p || [ -n "$p" ]; do printf '%s' '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde ' > "$p"; done < targets.txt; echo OK
Zsh
while IFS= read -r p || [ -n "$p" ]; do printf '%s' '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde ' > "$p"; done < targets.txt; echo OK
Fish
while read -l p; printf %s '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde ' > "$p"; end < targets.txt; echo OK
Nushell
for p in (open --raw targets.txt | lines) { "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\n" | save --raw $p }; print OKNift
paths := open("targets.txt").trim().split("\n"); for(p : paths) { f := file(p); f.open("w"); f.write("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\n"); f.save(); f.close() }; print("OK")Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
delete-tree-100000
| Measurement | Bash | Zsh | Fish | Nushell | Nift | GNU baseline |
|---|---|---|---|---|---|---|
| Median elapsed time0–7.890 s | ||||||
| Median s | 2.199 | 2.446 | 2.264 | 7.306 | 2.848 | 2.167 |
| p95 s | 2.743 | 2.575 | 2.396 | 7.608 | 3.151 | 2.662 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | batched GNU utilities |
| Zsh | batched GNU utilities |
| Fish | batched GNU utilities |
| Nushell | native filesystem API |
| Nift | native filesystem API |
| GNU baseline | direct GNU xargs + /usr/bin/rm |
Bash
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Zsh
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Fish
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; echo OK
Nushell
let paths = (open --raw targets.txt | lines); rm ...$paths; print OK
Nift
paths := open("targets.txt").trim().split("\n"); remove(paths); print("OK")GNU baseline
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --
Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
copy-small-10000
| Measurement | Bash | Zsh | Fish | Nushell | Nift | GNU baseline |
|---|---|---|---|---|---|---|
| Median elapsed time0–1.812 s | ||||||
| Median s | 0.524 | 0.523 | 0.529 | 1.678 | 0.768 | 0.515 |
| p95 s | 0.541 | 0.553 | 0.539 | 1.723 | 0.785 | 0.546 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | batched GNU utilities |
| Zsh | batched GNU utilities |
| Fish | batched GNU utilities |
| Nushell | native filesystem API |
| Nift | native filesystem API |
| GNU baseline | direct GNU xargs + /usr/bin/cp |
Bash
/usr/bin/xargs -0 -a targets.nul /usr/bin/cp -t copied --; echo OK
Zsh
/usr/bin/xargs -0 -a targets.nul /usr/bin/cp -t copied --; echo OK
Fish
/usr/bin/xargs -0 -a targets.nul /usr/bin/cp -t copied --; echo OK
Nushell
for p in (open --raw targets.txt | lines) { cp $p ("copied/" + ($p | path basename)) }; print OKNift
paths := open("targets.txt").trim().split("\n"); for(p : paths) { copy(p, "copied/" + p.split("/").last()) }; print("OK")GNU baseline
/usr/bin/xargs -0 -a targets.nul /usr/bin/cp -t copied --
Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
rename-selected-10000
| Measurement | Bash | Zsh | Fish | Nushell | Nift | GNU baseline |
|---|---|---|---|---|---|---|
| Median elapsed time0–1.267 s | ||||||
| Median s | 0.355 | 0.345 | 0.346 | 1.173 | 0.547 | 0.343 |
| p95 s | 0.366 | 0.356 | 0.386 | 1.269 | 0.584 | 0.364 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | batched GNU utilities |
| Zsh | batched GNU utilities |
| Fish | batched GNU utilities |
| Nushell | native filesystem API |
| Nift | native filesystem API |
| GNU baseline | direct GNU xargs + /usr/bin/mv |
Bash
/usr/bin/xargs -0 -a targets.nul /usr/bin/mv -t moved --; echo OK
Zsh
/usr/bin/xargs -0 -a targets.nul /usr/bin/mv -t moved --; echo OK
Fish
/usr/bin/xargs -0 -a targets.nul /usr/bin/mv -t moved --; echo OK
Nushell
for p in (open --raw targets.txt | lines) { mv $p ("moved/" + ($p | path basename)) }; print OKNift
paths := open("targets.txt").trim().split("\n"); for(p : paths) { move(p, "moved/" + p.split("/").last()) }; print("OK")GNU baseline
/usr/bin/xargs -0 -a targets.nul /usr/bin/mv -t moved --
Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
concat-small-10000
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–0.591 s | |||||
| Median s | 0.105 | 0.105 | 0.108 | 0.548 | 0.253 |
| p95 s | 0.117 | 0.112 | 0.124 | 0.573 | 0.275 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | batched GNU utilities |
| Zsh | batched GNU utilities |
| Fish | batched GNU utilities |
| Nushell | native filesystem API |
| Nift | native filesystem API |
Bash
/usr/bin/xargs -0 -a targets.nul /usr/bin/cat -- > output; echo OK
Zsh
/usr/bin/xargs -0 -a targets.nul /usr/bin/cat -- > output; echo OK
Fish
/usr/bin/xargs -0 -a targets.nul /usr/bin/cat -- > output; echo OK
Nushell
open --raw targets.txt | lines | each {|p| open --raw $p } | str join | save --raw output; print OKNift
paths := open("targets.txt").trim().split("\n"); dest := file("output"); dest.open("w"); for(p : paths) { dest.write(open(p)) }; dest.save(); dest.close(); print("OK")Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
metadata-10000
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–1.944 s | |||||
| Median s | 0.041 | 0.041 | 0.041 | 1.800 | 0.119 |
| p95 s | 0.047 | 0.044 | 0.044 | 1.847 | 0.130 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | batched GNU utilities |
| Zsh | batched GNU utilities |
| Fish | batched GNU utilities |
| Nushell | native filesystem API |
| Nift | native filesystem API |
Bash
/usr/bin/xargs -0 -a targets.nul /usr/bin/stat --printf='%s\n' -- | /usr/bin/awk '{s+=$1} END{printf "%.0f\n",s}'Zsh
/usr/bin/xargs -0 -a targets.nul /usr/bin/stat --printf='%s\n' -- | /usr/bin/awk '{s+=$1} END{printf "%.0f\n",s}'Fish
/usr/bin/xargs -0 -a targets.nul /usr/bin/stat --printf='%s\n' -- | /usr/bin/awk '{s+=$1} END{printf "%.0f\n",s}'Nushell
let total = (open --raw targets.txt | lines | each {|p| ls $p | get size | first | into int } | math sum); print $totalNift
paths := open("targets.txt").trim().split("\n"); total := 0; for(p : paths) { total += stat(p).size }; print(total)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
traverse-100000
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–1.116 s | |||||
| Median s | 0.483 | 0.483 | 0.486 | 0.255 | 1.033 |
| p95 s | 0.512 | 0.518 | 0.498 | 0.273 | 1.077 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | batched GNU utilities |
| Zsh | batched GNU utilities |
| Fish | batched GNU utilities |
| Nushell | native filesystem API |
| Nift | native filesystem API |
Bash
/usr/bin/find files -type f -name '*.dat' -printf '%s\n' | /usr/bin/awk '{n++;s+=$1} END{print n}'Zsh
/usr/bin/find files -type f -name '*.dat' -printf '%s\n' | /usr/bin/awk '{n++;s+=$1} END{print n}'Fish
/usr/bin/find files -type f -name '*.dat' -printf '%s\n' | /usr/bin/awk '{n++;s+=$1} END{print n}'Nushell
print (glob "files/**/*.dat" | length)
Nift
paths := ls("files/**/*.dat"); print(paths.size())Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
processes
Process scaling: 1 → 10 → 100 → 1,000
| Task size | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Elapsed time vs sizeLogarithmic task-size axis; lines connect measured points. | |||||
| 1 | 0.003 | 0.003 | 0.004 | 0.015 | 0.004 |
| 10 | 0.010 | 0.012 | 0.010 | 0.022 | 0.012 |
| 100 | 0.084 | 0.100 | 0.073 | 0.095 | 0.094 |
| 1000 | 0.850 | 0.973 | 0.685 | 0.819 | 0.910 |
processes-1
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| p95 | 0.003 | 0.003 | 0.004 | 0.016 | 0.004 |
| Minimum | 0.003 | 0.003 | 0.003 | 0.014 | 0.003 |
| Maximum | 0.003 | 0.003 | 0.004 | 0.016 | 0.004 |
| System | Implementation |
|---|---|
| Bash | common external utilities |
| Zsh | common external utilities |
| Fish | common external utilities |
| Nushell | common external utilities |
| Nift | common external utilities |
Bash
for ((i=0;i<1;i++)); do /usr/bin/true || exit 1; done; echo 1
Zsh
for ((i=0;i<1;i++)); do /usr/bin/true || exit 1; done; echo 1
Fish
set i 0; while test $i -lt 1; /usr/bin/true; or exit 1; set i (math $i + 1); end; echo $i
Nushell
for i in 1..1 { ^/usr/bin/true; if $env.LAST_EXIT_CODE != 0 { exit 1 } }; print 1Nift
i := 0; while(i < 1) { r := run("/usr/bin/true"); if(r.exit_code != 0) { print("FAIL") }; i += 1 }; print(i)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
processes-10
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| p95 | 0.011 | 0.013 | 0.011 | 0.024 | 0.012 |
| Minimum | 0.010 | 0.011 | 0.009 | 0.021 | 0.011 |
| Maximum | 0.012 | 0.014 | 0.011 | 0.024 | 0.012 |
| System | Implementation |
|---|---|
| Bash | common external utilities |
| Zsh | common external utilities |
| Fish | common external utilities |
| Nushell | common external utilities |
| Nift | common external utilities |
Bash
for ((i=0;i<10;i++)); do /usr/bin/true || exit 1; done; echo 10
Zsh
for ((i=0;i<10;i++)); do /usr/bin/true || exit 1; done; echo 10
Fish
set i 0; while test $i -lt 10; /usr/bin/true; or exit 1; set i (math $i + 1); end; echo $i
Nushell
for i in 1..10 { ^/usr/bin/true; if $env.LAST_EXIT_CODE != 0 { exit 1 } }; print 10Nift
i := 0; while(i < 10) { r := run("/usr/bin/true"); if(r.exit_code != 0) { print("FAIL") }; i += 1 }; print(i)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
processes-100
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| p95 | 0.090 | 0.105 | 0.079 | 0.100 | 0.099 |
| Minimum | 0.082 | 0.096 | 0.071 | 0.092 | 0.089 |
| Maximum | 0.091 | 0.106 | 0.080 | 0.100 | 0.100 |
| System | Implementation |
|---|---|
| Bash | common external utilities |
| Zsh | common external utilities |
| Fish | common external utilities |
| Nushell | common external utilities |
| Nift | common external utilities |
Bash
for ((i=0;i<100;i++)); do /usr/bin/true || exit 1; done; echo 100
Zsh
for ((i=0;i<100;i++)); do /usr/bin/true || exit 1; done; echo 100
Fish
set i 0; while test $i -lt 100; /usr/bin/true; or exit 1; set i (math $i + 1); end; echo $i
Nushell
for i in 1..100 { ^/usr/bin/true; if $env.LAST_EXIT_CODE != 0 { exit 1 } }; print 100Nift
i := 0; while(i < 100) { r := run("/usr/bin/true"); if(r.exit_code != 0) { print("FAIL") }; i += 1 }; print(i)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
processes-1000
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| p95 | 0.879 | 1.010 | 0.710 | 0.873 | 0.932 |
| Minimum | 0.804 | 0.947 | 0.674 | 0.792 | 0.892 |
| Maximum | 0.892 | 1.010 | 0.715 | 0.892 | 0.946 |
| System | Implementation |
|---|---|
| Bash | common external utilities |
| Zsh | common external utilities |
| Fish | common external utilities |
| Nushell | common external utilities |
| Nift | common external utilities |
Bash
for ((i=0;i<1000;i++)); do /usr/bin/true || exit 1; done; echo 1000
Zsh
for ((i=0;i<1000;i++)); do /usr/bin/true || exit 1; done; echo 1000
Fish
set i 0; while test $i -lt 1000; /usr/bin/true; or exit 1; set i (math $i + 1); end; echo $i
Nushell
for i in 1..1000 { ^/usr/bin/true; if $env.LAST_EXIT_CODE != 0 { exit 1 } }; print 1000Nift
i := 0; while(i < 1000) { r := run("/usr/bin/true"); if(r.exit_code != 0) { print("FAIL") }; i += 1 }; print(i)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
pipelines
Pipeline scaling: 2 → 4 → 8 stages
| Task size | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Elapsed time vs sizeLogarithmic task-size axis; lines connect measured points. | |||||
| 2 | 0.004 | 0.005 | 0.005 | 0.017 | 0.005 |
| 4 | 0.007 | 0.008 | 0.006 | 0.019 | 0.007 |
| 8 | 0.012 | 0.013 | 0.010 | 0.023 | 0.012 |
pipeline-2
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| p95 | 0.005 | 0.006 | 0.006 | 0.020 | 0.005 |
| Minimum | 0.004 | 0.005 | 0.004 | 0.015 | 0.005 |
| Maximum | 0.006 | 0.006 | 0.006 | 0.022 | 0.006 |
| System | Implementation |
|---|---|
| Bash | common external utilities |
| Zsh | common external utilities |
| Fish | common external utilities |
| Nushell | common external utilities |
| Nift | common external utilities |
Bash
/usr/bin/printf pipeline | /usr/bin/cat
Zsh
/usr/bin/printf pipeline | /usr/bin/cat
Fish
/usr/bin/printf pipeline | /usr/bin/cat
Nushell
^/usr/bin/printf pipeline | ^/usr/bin/cat
Nift
r := cmd("/usr/bin/printf", "pipeline").pipe(cmd("/usr/bin/cat")).run(); print(r.stdout)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
pipeline-4
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| p95 | 0.007 | 0.009 | 0.007 | 0.020 | 0.008 |
| Minimum | 0.006 | 0.007 | 0.006 | 0.018 | 0.007 |
| Maximum | 0.007 | 0.009 | 0.007 | 0.021 | 0.008 |
| System | Implementation |
|---|---|
| Bash | common external utilities |
| Zsh | common external utilities |
| Fish | common external utilities |
| Nushell | common external utilities |
| Nift | common external utilities |
Bash
/usr/bin/printf pipeline | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat
Zsh
/usr/bin/printf pipeline | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat
Fish
/usr/bin/printf pipeline | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat
Nushell
^/usr/bin/printf pipeline | ^/usr/bin/cat | ^/usr/bin/cat | ^/usr/bin/cat
Nift
r := cmd("/usr/bin/printf", "pipeline").pipe(cmd("/usr/bin/cat")).pipe(cmd("/usr/bin/cat")).pipe(cmd("/usr/bin/cat")).run(); print(r.stdout)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
pipeline-8
Implementations, invocations, tails and correctness
| Distribution · seconds | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| p95 | 0.014 | 0.014 | 0.014 | 0.028 | 0.014 |
| Minimum | 0.011 | 0.012 | 0.010 | 0.022 | 0.011 |
| Maximum | 0.015 | 0.014 | 0.014 | 0.032 | 0.015 |
| System | Implementation |
|---|---|
| Bash | common external utilities |
| Zsh | common external utilities |
| Fish | common external utilities |
| Nushell | common external utilities |
| Nift | common external utilities |
Bash
/usr/bin/printf pipeline | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat
Zsh
/usr/bin/printf pipeline | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat
Fish
/usr/bin/printf pipeline | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat | /usr/bin/cat
Nushell
^/usr/bin/printf pipeline | ^/usr/bin/cat | ^/usr/bin/cat | ^/usr/bin/cat | ^/usr/bin/cat | ^/usr/bin/cat | ^/usr/bin/cat | ^/usr/bin/cat
Nift
r := cmd("/usr/bin/printf", "pipeline").pipe(cmd("/usr/bin/cat")).pipe(cmd("/usr/bin/cat")).pipe(cmd("/usr/bin/cat")).pipe(cmd("/usr/bin/cat")).pipe(cmd("/usr/bin/cat")).pipe(cmd("/usr/bin/cat")).pipe(cmd("/usr/bin/cat")).run(); print(r.stdout)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
text
Text and Unix workflows
log-filter-group
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–0.064 s | |||||
| Median s | 0.046 | 0.048 | 0.046 | 0.059 | 0.048 |
| p95 s | 0.050 | 0.050 | 0.048 | 0.062 | 0.050 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | common external utilities |
| Zsh | common external utilities |
| Fish | common external utilities |
| Nushell | common external utilities |
| Nift | common external utilities |
Bash
/usr/bin/grep '^ERROR' logs.txt | /usr/bin/awk '{print $2}' | /usr/bin/sort | /usr/bin/uniq '-c'Zsh
/usr/bin/grep '^ERROR' logs.txt | /usr/bin/awk '{print $2}' | /usr/bin/sort | /usr/bin/uniq '-c'Fish
/usr/bin/grep '^ERROR' logs.txt | /usr/bin/awk '{print $2}' | /usr/bin/sort | /usr/bin/uniq '-c'Nushell
^/usr/bin/grep '^ERROR' logs.txt | ^/usr/bin/awk '{print $2}' | ^/usr/bin/sort | ^/usr/bin/uniq '-c'Nift
r := cmd("/usr/bin/grep", "^ERROR", "logs.txt").pipe(cmd("/usr/bin/awk", "{print $2}").pipe(cmd("/usr/bin/sort").pipe(cmd("/usr/bin/uniq", "-c")))).run(); print(r.stdout)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
This log filter/group workload uses the same grep → awk → sort → uniq engines in all shells. Its timings include orchestration and utility work; it does not compare five native text engines.
algorithms
Substantial logic in the shell
arithmetic
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–3.395 s | |||||
| Median s | 0.066 | 0.026 | 3.143 | 0.031 | 0.017 |
| p95 s | 0.067 | 0.037 | 3.416 | 0.036 | 0.018 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | native shell code |
| Zsh | native shell code |
| Fish | native shell code |
| Nushell | native shell code |
| Nift | native shell code |
Bash
s=0; for ((i=1;i<=20000;i++)); do s=$((s+i)); done; echo $s
Zsh
s=0; for ((i=1;i<=20000;i++)); do s=$((s+i)); done; echo $s
Fish
set s 0; set i 1; while test $i -le 20000; set s (math $s + $i); set i (math $i + 1); end; echo $s
Nushell
mut s = 0; for i in 1..20000 { $s = $s + $i }; print $sNift
s := 0; i := 1; while(i <= 20000) { s += i; i += 1 }; print(s)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
function-calls
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–1.462 s | |||||
| Median s | 0.053 | 0.142 | 1.354 | 0.044 | 0.022 |
| p95 s | 0.060 | 0.143 | 1.401 | 0.047 | 0.023 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | native shell code |
| Zsh | native shell code |
| Fish | native shell code |
| Nushell | native shell code |
| Nift | native shell code |
Bash
inc() { s=$((s+1)); }; s=0; for ((i=0;i<10000;i++)); do inc; done; echo $sZsh
inc() { s=$((s+1)); }; s=0; for ((i=0;i<10000;i++)); do inc; done; echo $sFish
function inc; set -g s (math $s + 1); end; set s 0; set i 0; while test $i -lt 10000; inc; set i (math $i + 1); end; echo $s
Nushell
def inc [x: int] { $x + 1 }; mut s = 0; for i in 1..10000 { $s = (inc $s) }; print $sNift
fn(inc(x)) { return x+1 }; s := 0; i := 0; while(i < 10000) { s = inc(s); i += 1 }; print(s)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
fibonacci-mod
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–0.162 s | |||||
| Median s | 0.008 | 0.005 | 0.150 | 0.016 | 0.004 |
| p95 s | 0.011 | 0.005 | 0.163 | 0.017 | 0.006 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | native shell code |
| Zsh | native shell code |
| Fish | native shell code |
| Nushell | native shell code |
| Nift | native shell code |
Bash
a=0; b=1; for ((i=0;i<1000;i++)); do t=$(((a+b)%1000000)); a=$b; b=$t; done; echo $a
Zsh
a=0; b=1; for ((i=0;i<1000;i++)); do t=$(((a+b)%1000000)); a=$b; b=$t; done; echo $a
Fish
set a 0; set b 1; set i 0; while test $i -lt 1000; set t (math "($a + $b) % 1000000"); set a $b; set b $t; set i (math $i + 1); end; echo $a
Nushell
mut a = 0; mut b = 1; for i in 1..1000 { let t = (($a + $b) mod 1000000); $a = $b; $b = $t }; print $aNift
a := 0; b := 1; i := 0; while(i < 1000) { t := (a+b)%1000000; a=b; b=t; i+=1 }; print(a)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
string-transform
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–0.899 s | |||||
| Median s | 0.036 | 0.014 | 0.832 | 0.047 | 0.019 |
| p95 s | 0.041 | 0.018 | 0.873 | 0.051 | 0.019 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | native shell code |
| Zsh | native shell code |
| Fish | native shell code |
| Nushell | native shell code |
| Nift | native shell code |
Bash
for ((i=0;i<5000;i++)); do s=alpha; s=${s^^}; s=${s//A/a}; done; echo $sZsh
for ((i=0;i<5000;i++)); do s=alpha; s=${(U)s}; s=${s//A/a}; done; echo $sFish
set i 0; while test $i -lt 5000; set s (string upper alpha | string replace -a A a); set i (math $i + 1); end; echo $s
Nushell
mut s = ""; for i in 1..5000 { $s = ("alpha" | str upcase | str replace -a A a) }; print $sNift
s := "alpha"; i := 0; while(i < 5000) { s="alpha".to_upper().replace("A","a"); i+=1 }; print(s)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
Four bounded native scripting cases cover arithmetic, calls, iterative modular Fibonacci and string transforms. Fish uses its builtin math/test/string operations; builtin pipelines and command substitutions still incur shell machinery. No deliberately pathological recursion or unsupported map API is forced onto a participant.
real-world
Mixed workflows
source-tree-report
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–0.258 s | |||||
| Median s | 0.220 | 0.226 | 0.229 | 0.239 | 0.230 |
| p95 s | 0.233 | 0.250 | 0.236 | 0.263 | 0.256 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | common find → xargs/wc → awk pipeline |
| Zsh | common find → xargs/wc → awk pipeline |
| Fish | common find → xargs/wc → awk pipeline |
| Nushell | common find → xargs/wc → awk pipeline |
| Nift | common find → xargs/wc → awk pipeline |
Bash
/usr/bin/find files -type f -print0 | /usr/bin/xargs -0 /usr/bin/wc -lc | /usr/bin/awk '{e=$3; sub(/^.*[.]/,"",e); if($3!="total") {c[e]++;b[e]+=$2;l[e]+=$1}} END{print "cc",c["cc"],b["cc"],l["cc"];print "dat",c["dat"],b["dat"],l["dat"];print "md",c["md"],b["md"],l["md"];print "py",c["py"],b["py"],l["py"]}'Zsh
/usr/bin/find files -type f -print0 | /usr/bin/xargs -0 /usr/bin/wc -lc | /usr/bin/awk '{e=$3; sub(/^.*[.]/,"",e); if($3!="total") {c[e]++;b[e]+=$2;l[e]+=$1}} END{print "cc",c["cc"],b["cc"],l["cc"];print "dat",c["dat"],b["dat"],l["dat"];print "md",c["md"],b["md"],l["md"];print "py",c["py"],b["py"],l["py"]}'Fish
/usr/bin/find files -type f -print0 | /usr/bin/xargs -0 /usr/bin/wc -lc | /usr/bin/awk '{e=$3; sub(/^.*[.]/,"",e); if($3!="total") {c[e]++;b[e]+=$2;l[e]+=$1}} END{print "cc",c["cc"],b["cc"],l["cc"];print "dat",c["dat"],b["dat"],l["dat"];print "md",c["md"],b["md"],l["md"];print "py",c["py"],b["py"],l["py"]}'Nushell
^/usr/bin/find files -type f -print0 | ^/usr/bin/xargs -0 /usr/bin/wc -lc | ^/usr/bin/awk '{e=$3; sub(/^.*[.]/,"",e); if($3!="total") {c[e]++;b[e]+=$2;l[e]+=$1}} END{print "cc",c["cc"],b["cc"],l["cc"];print "dat",c["dat"],b["dat"],l["dat"];print "md",c["md"],b["md"],l["md"];print "py",c["py"],b["py"],l["py"]}'Nift
r := cmd("/usr/bin/find", "files", "-type", "f", "-print0").pipe(cmd("/usr/bin/xargs", "-0", "/usr/bin/wc", "-lc")).pipe(cmd("/usr/bin/awk", "{e=$3; sub(/^.*[.]/,\"\",e); if($3!=\"total\") {c[e]++;b[e]+=$2;l[e]+=$1}} END{print \"cc\",c[\"cc\"],b[\"cc\"],l[\"cc\"];print \"dat\",c[\"dat\"],b[\"dat\"],l[\"dat\"];print \"md\",c[\"md\"],b[\"md\"],l[\"md\"];print \"py\",c[\"py\"],b[\"py\"],l[\"py\"]}")).run(); print(r.stdout)Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
selected-cleanup
| Measurement | Bash | Zsh | Fish | Nushell | Nift |
|---|---|---|---|---|---|
| Median elapsed time0–0.117 s | |||||
| Median s | 0.032 | 0.033 | 0.035 | 0.109 | 0.045 |
| p95 s | 0.035 | 0.036 | 0.042 | 0.115 | 0.049 |
Implementations, invocations, tails and correctness
| System | Implementation |
|---|---|
| Bash | batched GNU utilities |
| Zsh | batched GNU utilities |
| Fish | batched GNU utilities |
| Nushell | native filesystem API |
| Nift | native filesystem API |
Bash
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; /usr/bin/mkdir report; /usr/bin/xargs -0 -a outputs.nul /usr/bin/mv -t report --; printf "deleted=1000 archived=200" > report/summary; echo OK
Zsh
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; /usr/bin/mkdir report; /usr/bin/xargs -0 -a outputs.nul /usr/bin/mv -t report --; printf "deleted=1000 archived=200" > report/summary; echo OK
Fish
/usr/bin/xargs -0 -a targets.nul /usr/bin/rm --; /usr/bin/mkdir report; /usr/bin/xargs -0 -a outputs.nul /usr/bin/mv -t report --; printf "deleted=1000 archived=200" > report/summary; echo OK
Nushell
for p in (open --raw targets.txt | lines) { rm $p }; mkdir report; let outputs = (open --raw outputs.txt | lines); mv ...$outputs report; "deleted=1000 archived=200" | save --raw report/summary; print OKNift
paths := open("targets.txt").trim().split("\n"); for(p : paths) { remove(p) }; make_dir("report"); for(p : open("outputs.txt").split("\n")) { move(p, "report/" + p.split("/").last()) }; f := file("report/summary"); f.open("w"); f.write("deleted=1000 archived=200"); f.save(); f.close(); print("OK")Every observation passed its output and filesystem oracle. Reconstructed fixture setup and verification are outside elapsed time. Exact source, manifest and oracle hashes, commands, samples, waited-child high-water RSS and validation records are preserved in shell-workloads.json.
The common Unix report groups a synthetic .py/.cc/.md tree plus keepers by extension, counting files, bytes and lines. Cleanup deletes its exact temporary-file manifest, preserves keepers, moves 200 outputs into a report directory and writes a verified summary. These combine filesystem APIs and orchestration rather than pretending to isolate an interpreter.
Correctness / limits
Fast and wrong does not qualify.
The additive workload layer retains 1,275 measured observations and 255 warmups across 141 jobs. Ordinary cases use 10 + 2; heavyweight 100k cases use 5 + 1. Each sample reconstructs and checks its fixture before timing, then checks complete output and filesystem postconditions afterwards. Runtime-native, orchestration, end-to-end and direct GNU baselines stay separate. New case order and participant order within each case rotate. Waited-child RSS is retained in raw data but does not measure simultaneous aggregate process-tree memory.
The compiled PTY bridge avoids Python heap fork latency. Minimal probe measurements disclose remaining launch/forwarding/scheduling overhead; differences near that floor need care.
Complete-state certification before and after collection validates every synthetic variable/function, conditional and PATH prefix. These final startup results are direct measurements, with no subtraction of RC-body diagnostics.
Non-interactive invocations must exit successfully and yield expected output. PTY timing ends at prompt arrival, followed by its command/state oracle; the bridge then terminates the child process group, so a natural-exit status and teardown RSS are outside that boundary. Failures retain non-publishable evidence. Prepared startup cells contain 100 samples; fresh-state startup cells contain 30; both have 3 retained warmups. Configured fresh Zsh rebuilds system completion state, so its expensive series uses 30 samples, frozen before collection. No sample was excluded. Work cells contain 10 plus 3. Order rotates each round.
An allowlisted environment and job-specific HOME/XDG/ZDOTDIR prevent BASH_ENV, ENV, inherited functions, personal dotfiles or tokens from entering measured processes. Terminal queries receive documented xterm responses. OSC 133 prompt completion is used where available, otherwise prompt suffix detection; the oracle proves the shell is usable afterwards. This terminal model affects interactive startup and limits generalisation.
Configuration discovery, parsing, history and lazy initialization can interact. No additive RC decomposition is justified. Rich runtime features and low bare startup answer different engineering questions.
Separate recovery diagnostic
Same-node checks for the surprising changes.
Separate same-node diagnostic: exact clean source builds c8d9c266 (previous release), 7f7e487 (original candidate) and c14d068 (final), using the same GCC 13.3 / native Make -O2 configuration, CPU 0, ten measured samples plus two warmups per case/version, six-permutation adjacent ordering and unchanged source/output oracles. All 72 observations passed independent audit; these are not pooled into official peer tables.
| Case | Release ms | Original candidate ms | Final candidate ms |
|---|---|---|---|
| function-calls | 20.989 | 44.971 | 21.655 |
| string-transform | 59.696 | 66.950 | 18.680 |
Calls improved 51.85% from the original candidate; final versus release differed by 0.666 ms (+3.17%), with overlapping ranges. Strings improved 72.10% versus the original and 68.71% versus release, with disjoint ranges and all ten paired final observations faster. These are fixed-specimen gains, not universal language-speed claims.
Findings and qualifications · All raw samples and build identities · Independent audit.
Practitioner judgement / AI-DX
Choose for the actual workflow.
For established POSIX shell compatibility I would retain Bash or Zsh; interactive preferences and structured-data workflows can favor Fish or Nushell. For authored Nift-owned automation, agent-maintained mixed projects and workflows needing programmable .f policy plus explicit artifact/input/lifecycle contracts, I would choose Nift. That is a contextual practitioner preference, not a claim of drop-in shell equivalence or universal speed leadership. Direct GNU helper-only baselines are excluded from shell peer rankings because their launch boundary differs.
Machine-readable inputs, ownership and dependencies can be useful explicitness rather than redundant ceremony. These qualitative judgements do not turn the harness’s golden-output/fixture checks into automatic product guarantees. Memory remains a separately qualified waited-child high-water measure, not aggregate process-tree usage or a combined performance score.
Frozen environment
Exact source, tools and boundaries.
Final candidate Nift 4.12.0, exact clean source c14d06835bca515a5281e41da0e40219c2d60ef0; CLI SHA-256 7dd42dcee5ca4a6965f0823c0ae59198282da1eb77e0fcd4cae93a537870a6fb. Native Make -O2, GCC 13.3; dedicated g6-standard-4 (8 GB / four vCPUs), Ubuntu 24.04, timed processes pinned to CPU 0. OS caches are uncontrolled; this is not machine-cold timing. Historical hosts and diagnostic cohorts are never pooled.
| System | Measured version |
|---|---|
| bash | GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu) |
| zsh | zsh 5.9 (x86_64-ubuntu-linux-gnu) |
| fish | fish, version 4.9.3 |
| nu | 0.116.1 |
| nift | Nift v4.12.0 |
Exact build identity · Frozen suite and tool pins · Actual compiler/package inventory.
Independent complete-count/distribution audit · Normalized measurements · Complete raw data and retained warmups. No failed or superseded attempt is substituted for this accepted series.
Reproduce / scrutinise
All observations are retained.
Complete accepted series; the frozen suite revision and exact invocation are recorded in its readiness and official controller files. Summaries are independently recomputed from raw observations.
Conclusion
Startup and substantial work, with boundaries.
These observations describe the frozen startup/configuration paths and checked filesystem, orchestration and native scripting tasks. It does not establish a universally fastest shell, feature parity, or machine-cold performance.
Nift Benchmarks