shish
A small POSIX-ish shell in C. One file, no stdio,
no dialect of its own — and it compiles to WebAssembly.
- 139 KB stripped
- 184 KB of WebAssembly
- 26 k lines of C
- 0 runtime dependencies
Three places a 139 KB shell changes the maths
Containers
A distroless image with a shell in it usually means a libc, a loader
and a pile of coreutils binaries, just so the entrypoint can run
mkdir -p and a for loop.
shish has cat, rm, mkdir,
mktemp, ln, chmod,
uname and friends compiled in. The entrypoint runs with
PATH= empty and nothing else in the image.
Containers →
Agent sandboxes
An AI harness runs thousands of shell commands inside a boundary
somebody has to review. bash is 1.4 MB, a startup-file search path,
a history file and $BASH_ENV.
shish reads no startup file of its own, writes no history,
starts in ~1.3 ms, and -n parses a generated command
without running it.
Agent sandboxes →
WebAssembly
184 KB of .wasm: a real shell in a browser tab, a
worker, or a WASI runtime — with no process and no container
underneath it.
Subshells and command substitution are in-process, so
$(...) and ( ... ) work even where
fork() does not exist.
Playground →
A shell that does not need a /bin
shish -c 'PATH=; mkdir -p a/b; echo hi > a/b/f; cat a/b/f; rm -r a'
hi
Every utility in that line is inside the binary. Nothing is looked up,
so nothing can be planted on a PATH — see
Builtins for the full set and how to
choose it at compile time.
| shell | size | needs coreutils |
| shish | 139 KB | no (builtins) |
| dash | 126 KB | yes |
| bash | 1.4 MB | yes |
| busybox (sh + ~400 applets) | 2.0 MB | no |
Stripped x86-64 binaries on the same machine, dynamically
linked. shish is ~1.05 MB static with every builtin compiled in.
No dialect of its own
shish will never introduce a language construct that is not already in
POSIX or in another shell. Everything it accepts beyond the standard —
local, source, brace expansion, history
expansion — is spelled the way bash, ksh or dash already spells it, and
is an option rather than the default.
A script written for shish keeps running under sh.
That is the whole point: the small shell is a deployment choice, not a
language you have to learn or a lock-in you have to migrate off.
Build it
git clone https://github.com/rsenn/shish.git && cd shish
cmake -S . -B build/x86_64-linux-gnu
cmake --build build/x86_64-linux-gnu -j
Cross-builds for musl, dietlibc, mingw32/64, MSYS, aarch64,
Android, Termux, Emscripten and WASI all come from the same tree —
see Building.
Status: alpha, and honest about it
shish runs the shell language — pipelines, redirections, functions,
case, loops, parameter expansion, arithmetic, job control,
traps — and passes 5541 cases of yash's POSIX conformance suite.
It also still fails 551, mostly in signal disposition,
alias and quoting/parameter expansion.
It is not a drop-in /bin/sh yet: do not point
init at it. Every known defect has a repro in
BUGS, the work plan is in
TODO.md, and every fix ships
with a regression test. See Conformance
for the numbers behind that.