Help us measure site usage?

With your permission, we use self-hosted analytics to understand page usage. It is optional and does not affect the Service. Learn more.

CintermediatecliAI generated

Mini Unix Shell with Pipes and Redirection

Build your own Unix shell in C, a small version of bash: it shows a prompt, reads a command, and runs it, supporting pipes (ls | grep txt | wc -l), redirection (sort < in.txt > out.txt, and >> to append), quoted arguments, and built-in commands like cd, pwd and exit. Pressing Ctrl+C stops the running command but not the shell, and the shell reports when a command fails. Writing a shell is a classic way to understand how Unix really runs programs: you'll learn fork, execvp and waitpid, file descriptors with pipe and dup2, parsing input, built-in commands, and signal handling.

Estimate
~12h
Steps
7
Completed by
0
Proposed by
codeseed.app

unistd.h · sys/wait.h · fcntl.h

Project roadmap

  1. 01

    Read and split commands

    ~2h

    Write the main loop: print a prompt, read a line with getline (exit on end of input), and split it into tokens, treating text in single or double quotes as one token and recognizing |, <, > and >> as separate tokens even without spaces around them. Report unclosed quotes. Done when: unit tests show echo "a b" c|wc>out.txt splits into the right tokens.

  2. 02

    Run a single command

    ~1.5h

    For a simple command, fork a child that calls execvp with the arguments, and have the parent wait with waitpid. If execvp fails, print command not found (using the errno) and exit the child with code 127. Keep the last exit status. Done when: running ls -l and a made-up command behave like in bash.

  3. 03

    Add redirection

    ~1.5h

    Parse < file, > file and >> file into the command structure. In the child, before execvp, open the files with the right flags (O_RDONLY, or O_WRONLY | O_CREAT with O_TRUNC or O_APPEND, and mode 0644) and connect them to standard input or output with dup2, closing the originals. Report files that can't be opened. Done when: sort < in.txt > out.txt and echo hi >> log.txt work like in bash.

  4. 04

    Connect commands with pipes

    ~2.5h

    Split the line into stages at | and, for N stages, create N-1 pipes. Fork each stage, connect its input to the previous pipe's read end and its output to the next pipe's write end with dup2, and close every unused pipe end in every process (otherwise commands like wc never finish). Wait for all stages and use the last stage's status. Done when: ls | grep c | wc -l gives the same result as bash.

  5. 05

    Add built-in commands

    ~1h

    Handle cd (with no argument going to HOME, and cd - going back), pwd, exit (with an optional status) and a status command showing the last exit code, directly in the shell process without forking, since cd in a child wouldn't change the shell's directory. Done when: cd changes the prompt's directory, and exit 3 exits with status 3.

  6. 06

    Handle Ctrl+C and report status

    ~1.5h

    Make the shell ignore SIGINT (so Ctrl+C doesn't kill it), and restore the default in child processes before execvp, so Ctrl+C stops the running command. Print a message when a command is killed by a signal or exits with a non-zero status. Done when: Ctrl+C stops sleep 100 without closing the shell.

  7. 07

    Test it

    ~2h

    Write a test script that feeds commands to your shell through standard input and compares the output with bash for pipes, redirection, quotes, built-ins and errors. Check for leaked file descriptors (for example by listing /proc/self/fd in a child) and run it under valgrind. Done when: all comparisons match, with no leaks.

Ready to build this?

Get a GitHub repo and start building. Your AI reviewer checks each step as you go.

~12h · 7 steps

Tech stack

unistd.hsys/wait.hfcntl.h