Unix Shell with Pipes, Redirection and Job Control
An operating systems final year project: build a working Unix shell in C with built-ins, redirection, pipelines of any length and background jobs with job control, plus a test harness that compares it with bash or dash. Each feature teaches one OS idea (fork and exec, file descriptors, signals, process groups), and the harness can become a reusable lab resource.
Intermediate
A small team, or one strong student willing to learn something new.8 to 10 weeks · 1 student
8 to ship
3 optional extrasSuggested stack
What you should ship
- A read, parse, execute loop that runs external programs with fork, execvp and waitpid, with clear errors for unknown commands
- A hand-written tokenizer and parser for words, simple quoting, pipes, redirection and the background operator
- Built-in commands cd, exit, pwd, export and history, with a written explanation of why cd cannot run in a child
- Input and output redirection with <, > and >> using dup2, closing every unused file descriptor
- Pipelines of any length, with pipe ends closed in the right processes so readers see end of file
- Background jobs with &, a jobs command, fg and bg, process groups, terminal control and correct Ctrl+C and Ctrl+Z handling
- Zero zombie processes and zero leaked descriptors after a scripted session, checked with Valgrind and /proc
- An automated harness of at least 60 cases comparing output and exit status with bash or dash, run in CI
If you have time left
- Environment variable expansion, exit status in $? and && and || operators
- Tab completion for file names and commands using readline or a small line editor
- A tracing mode that prints every system call the shell makes for a command, for teaching
The problem: processes stay abstract until you build a shell
Operating systems courses teach fork, exec, file descriptors and signals as separate slides. Many students pass the exam and still cannot explain why "cd" is a built-in or why a pipeline hangs when one end is left open. The gap shows up later when they debug a container that will not stop, a script that leaks processes, or a service that ignores signals.
A shell is the operating systems course in one program. Running one command means creating a process, replacing its image and waiting for it. Redirection teaches file descriptors, pipelines teach how processes share data through the kernel, and job control teaches signals and process groups.
What already exists and the gap
- bash and dash are the reference shells: complete, standards-following and far too large to learn from line by line.
- fish shows how a modern interactive shell can prioritise usability over POSIX compatibility.
- The Shell Lab in the CS:APP textbook course material has students write a small shell with job control.
- CodeCrafters' Build your own Shell challenge walks through parsing and running commands step by step.
The gap is verification and teaching value. Guided challenges and lab handouts usually stop when the feature works on the happy path. This project adds a differential test harness that runs the same inputs through your shell and a reference shell, compares output and exit codes, and checks for leaked descriptors and zombies. That harness is useful beyond your own shell: a teaching assistant could reuse it to test student submissions.
What you build
- A prompt loop that reads a line, tokenizes it and parses it into a pipeline of commands with redirections.
- Execution of external programs, with errors that match what users expect.
- Built-ins that must run inside the shell process.
- Redirection with dup2, and pipelines of any length.
- Job control: each pipeline in its own process group, a jobs table, fg and bg, and the terminal handed to the foreground job.
- The differential harness and CI.
Grow it one feature at a time and keep every earlier feature passing its tests.
The technically interesting part
Job control and signals. The shell must put each job in its own process group, give the terminal to the foreground group with tcsetpgrp, ignore SIGINT and SIGTSTP itself while its children do not, and reap children with SIGCHLD without racing against the main loop. Races here produce bugs that appear once in fifty runs.
Show your supervisor a state diagram for a job (running, stopped, done), the signal masking you used around fork to avoid races, and a stress test that starts and stops hundreds of background jobs while checking the jobs table stays correct.
How to evaluate it
- Differential tests: at least 60 cases compared with bash or dash on output and exit status, including empty lines, missing files, long pipelines and failing commands; report pass rate.
- Resource hygiene: after a scripted session, zero zombies and zero leaked descriptors, shown with /proc and Valgrind.
- Race testing: repeat the job control stress test 100 times; report failures before and after fixes.
- Explanation: a README mapping each feature to the system calls it uses, with strace output for one pipeline.
Suggested plan
- Weeks 1 to 2: prompt loop, tokenizer, parser, running single commands, harness skeleton.
- Weeks 3 to 4: built-ins, redirection, pipelines.
- Weeks 5 to 7: process groups, signals, jobs, fg and bg.
- Weeks 8 to 9: stress tests, leak checks, bug fixing.
- Week 10: README, strace walkthrough, demo.
Path to a product
This is not a SaaS idea, and it should not pretend to be one. The realistic outcomes are two. First, a portfolio centrepiece for systems, embedded and infrastructure roles, where "I wrote a shell with job control and a test harness" leads to good interview conversations. Second, the harness and a tracing mode can be offered to your OS course as a lab resource, which is a genuine contribution your department can use.
Scope warning
Do not attempt full POSIX shell scripting, functions, arithmetic or here-documents. Do not use a parser generator: hand-write a small parser. Build it in C on Linux or WSL; a Python prototype is fine for exploring, but C shows the system calls directly. This is a common course assignment: if your university sets a similar one, follow its rules and do not publish solutions to an assignment still in use.
Learn what you need on Sefism
- Operating Systems: Three Easy Pieces : processes, the process API and signals explained clearly.
- MIT 6.1810: Operating System Engineering : a deeper look at how the kernel implements what your shell calls.
- explainshell : see how real shell command lines break down.
- Greg's Wiki: BashGuide : the behaviour your differential tests compare against.
- Programming cheat sheet : C and debugging reminders while you work.
- DSA roadmap : parsing and data structures for the jobs table.
Get help with this idea
Job control is where most shells stall, so plan your weeks around it. A mentor can help you set the feature cut-off, design the differential harness and prepare to explain your signal handling to examiners. If you are new here, create a free account first.
Ideas and guidance, not finished projects
These are project ideas and scoping guidance, published free for students to use as a starting point. I do not build, write, or sell final-year projects, and I do not complete coursework for anyone. Take an idea, make it yours, and build it.
Not sure this one fits you?
I help students pick an idea that matches their skills and their deadline, then scope it down until it is finishable. Guidance only, never done for you.
Stuck on something specific?
Writing only gets you so far. If you want an answer to your situation rather than the general case, book a session and we will work through it together. Sessions are free for approved Sefism members, and a few slots open each week.
Follow along
New writing, resources and project ideas land here first.