Build Your Own Shell
A POSIX-style shell written in TypeScript on Bun, with quoting, redirection, pipelines, background jobs, tab completion and persistent history.
- Period
- Context
- My role
The problem
A shell looks simple until you write one. Quoting rules, file descriptors, child processes, and a prompt that has to stay responsive while jobs run in the background all have to behave the way people expect from bash.
How it was built
A tokenizer with three modes
Input is read character by character in one of three modes: unquoted, single-quoted or double-quoted. Backslashes escape anything outside quotes but only \ and " inside double quotes, and $VAR and ${VAR} are expanded everywhere except inside single quotes.
Builtins that behave like programs
echo, cd, pwd, type, history, jobs, complete and declare write through an output function instead of straight to the terminal. That lets them be redirected with >, >>, 2> and 2>>, and take part in pipelines next to external programs found on PATH.
Jobs, completion and history
A trailing & starts a background job with a job number that is reused once it is free, and finished jobs are reported before the next prompt with the same +/- markers bash uses. Tab completion covers builtins, PATH executables, files and directories, plus programmable completion through complete -C scripts. History loads from HISTFILE and only new entries are appended on exit.
Where it landed
- Every stage of the challenge completed
- About 1,100 lines of TypeScript with no runtime dependencies
- Clone the repo and run it locally with Bun
Specification
- Runtime
- Parsing
- I/O
- Jobs
- Run locally