shish
A small POSIX-ish shell in C. One file, no stdio,
no dialect of its own. It compiles to WebAssembly.
- 197 KBstripped
- 184 KBof WebAssembly
- 26 klines of C
- 0runtime dependencies
Three places a 197 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 ~0.9 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 | 197 KB | no (builtins) |
| dash | 127 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.2 MB static with the default builtins, 2.8 MB with every builtin.
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
triplet=$(gcc -dumpmachine)
cmake -S . -B build/$triplet
cmake --build build/$triplet -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. It passes 6151 cases of yash's POSIX conformance suite.
It still fails 7, in alias, input,
quoting, and two deliberate departures (echo and
cat run as builtins even when PATH is empty).
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.