Project 1: Build a Shell Pipeline Executor

A program that executes cmd1 | cmd2 | cmd3 by creating pipes and forking processes, just like a real shell.

Quick Reference

Attribute Value
Primary Language C
Alternative Languages Rust, Go
Difficulty Level 2 (Intermediate)
Time Estimate See main guide
Knowledge Area Operating Systems, Process Management
Tooling None (pure syscalls)
Prerequisites See main guide

What You Will Build

A program that executes cmd1 | cmd2 | cmd3 by creating pipes and forking processes, just like a real shell.

Why It Matters

This project builds core skills that appear repeatedly in real-world systems and tooling.

Core Challenges

  • File descriptor management → Understanding dup2() and close()
  • Process coordination → Multiple fork() calls, parent waiting for children
  • EOF handling → Why closing write ends matters

Key Concepts

  • Map the project to core concepts before you code.

Real-World Outcome

# 1. Compile your pipeline executor
$ gcc -o mypipe mypipe.c
# No errors

# 2. Run a simple two-command pipeline
$ ./mypipe "ls -la" "grep txt"
-rw-r--r-- 1 user user  1234 Jan  1 12:00 notes.txt
-rw-r--r-- 1 user user  5678 Jan  1 12:00 data.txt

# 3. TEST: Three-command pipeline
$ ./mypipe "cat /etc/passwd" "grep root" "cut -d: -f1"
root
# Output shows only "root" - data flowed through all three commands

# 4. TEST: Verify no file descriptor leaks
$ ./mypipe "ls" "cat" &
$ ls -la /proc/$!/fd
total 0
lrwx------ 1 user user 64 Jan  1 12:00 0 -> /dev/pts/0
lrwx------ 1 user user 64 Jan  1 12:00 1 -> /dev/pts/0
lrwx------ 1 user user 64 Jan  1 12:00 2 -> /dev/pts/0
# Only 0,1,2 - no leaked pipe fds!

# 5. TEST: Verify no zombie processes
$ ./mypipe "sleep 1" "cat"
$ ps aux | grep defunct
# No output - no zombies

Implementation Guide

  1. Reproduce the simplest happy-path scenario.
  2. Build the smallest working version of the core feature.
  3. Add input validation and error handling.
  4. Add instrumentation/logging to confirm behavior.
  5. Refactor into clean modules with tests.

Milestones

  • Milestone 1: Minimal working program that runs end-to-end.
  • Milestone 2: Correct outputs for typical inputs.
  • Milestone 3: Robust handling of edge cases.
  • Milestone 4: Clean structure and documented usage.

Validation Checklist

  • Output matches the real-world outcome example
  • Handles invalid inputs safely
  • Provides clear errors and exit codes
  • Repeatable results across runs

References

  • Main guide: UNIX_IPC_STEVENS_VOL2_MASTERY.md
  • “Advanced Programming in the UNIX Environment” by Stevens & Rago