$_ shish

shish

A small POSIX-ish shell in C. One file, no stdio, no dialect of its own. It compiles to WebAssembly.

Get started Run it in your browser GitHub

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.

shellsizeneeds coreutils
shish197 KBno (builtins)
dash127 KByes
bash1.4 MByes
busybox (sh + ~400 applets)2.0 MBno

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.