๐งต Advanced Shell Process Control
๐ง Overview
Process control is where the shell stops being โa command runnerโ and becomes a process orchestrator. This includes:
- process groups
- job control
- signal delivery
- foreground/background execution
- subshells
- zombies and reaping
- traps
- PID 1 behavior in containers
This is one of the most misunderstood areas of shell behavior โ and one of the most critical for production systems.
๐ Who this is for
- DevOps/SRE managing longโrunning scripts, daemons, or containers
- Engineers writing orchestration logic or supervising child processes
- Anyone debugging zombies, hanging pipelines, or broken signal handling
- People who want deterministic, productionโgrade process behavior
๐งฉ Role in the Ecosystem
Process control is the backbone of:
- Subshells & Environment
- Traps & Signals
- Advanced Pipelines
- container entrypoints
- CI/CD runners
- daemon supervision
- job control in interactive shells
Without understanding process groups, sessions, and signal propagation, shell scripts behave unpredictably under load, in pipelines, or inside containers.
๐งฉ Internals / Mechanics
๐งฉ The shell as a process controller
A shell manages:
- processes (PIDs)
- process groups (PGIDs)
- sessions
- terminal control
- signal routing
- job tables
When you run:
1 | |
the shell:
- creates pipes
- forks children
- assigns them to a process group
- optionally puts the group in the background
- tracks them in the job table
๐งฉ Foreground vs background
- Foreground job owns the terminal โ receives
SIGINT,SIGQUIT, etc. - Background job does NOT own the terminal โ signals must be sent manually.
๐งฉ Process groups
A pipeline typically shares a process group:
1 | |
All three commands receive SIGINT when you press CtrlโC.
๐งฉ Subshells and isolation
Subshells:
- have their own PID
- do NOT share variable state
- inherit environment
- inherit file descriptors unless redirected
See also: Subshells & Environment
๐ง Techniques
๐ง Use wait to reap children
1 2 3 | |
Prevents zombies.
๐ง Use trap for clean shutdown
1 | |
๐ง Use process substitution to avoid unnecessary subshells
1 | |
๐ง Use set -m (job control) only in interactive shells
Never enable job control in scripts.
โ ๏ธ Pitfalls
โ ๏ธ Zombie processes from unreaped children
1 2 | |
โ ๏ธ CtrlโC not stopping pipelines
If the shell is not managing process groups correctly, only the foreground process receives SIGINT.
โ ๏ธ Traps not firing in subshells
1 | |
The trap runs in the subshell, not the parent.
โ ๏ธ Using kill -9 as a default
SIGKILL prevents cleanup and can corrupt state.
๐จ RealโWorld Failures
๐จ Failure: Shell script used as PID 1 leaks zombies
In Docker:
1 | |
sh becomes PID 1 โ does NOT reap children โ zombies accumulate.
Fix:
- use
tiniordumb-init - or implement a SIGCHLD handler +
wait
๐จ Failure: CI job hangs due to orphaned background process
1 2 | |
The background process keeps running โ CI never finishes.
Fix:
1 | |
๐จ Failure: CtrlโC doesnโt stop a pipeline
1 | |
If the shell doesnโt set a unified process group, only cmd2 receives SIGINT.
๐ ๏ธ Patterns
๐ ๏ธ Pattern: Explicit signal handling
1 | |
๐ ๏ธ Pattern: Use wait for all children
1 2 3 4 5 6 7 8 9 | |
๐ ๏ธ Pattern: Use a minimal init in containers
tini or dumb-init solves:
- zombie reaping
- signal forwarding
- predictable shutdown
โ AntiโPatterns
โ Using shell as a process supervisor
Shell is not systemd. Avoid:
- longโrunning loops
- manual restarts
- complex signal routing
โ Ignoring SIGCHLD
Leads to zombie accumulation.
โ Running background jobs without cleanup
1 2 | |
๐ Debugging
๐ Inspect process tree
1 2 | |
๐ Inspect process groups
1 | |
๐ Trace signals
1 | |
โ๏ธ Performance
โ๏ธ Avoid excessive forking
Use builtins where possible.
โ๏ธ Avoid longโrunning background loops
They consume CPU and complicate shutdown.
โ๏ธ Use wait -n (Bash) for efficient worker pools
๐ณ Containers
๐ณ Shell as PID 1
PID 1 has special semantics:
- ignores some signals by default
- must reap children
- must forward signals
๐ณ Use an init wrapper
1 2 | |
๐ฐ๏ธ CI/CD
๐ฐ๏ธ Ensure deterministic shutdown
CI runners kill jobs with SIGTERM โ scripts must handle it.
๐ฐ๏ธ Avoid background jobs unless necessary
They often outlive the job and cause hangs.
๐งช Testing
1 | |
1 2 | |
1 2 3 | |
๐ง Summary
Process control is the backbone of reliable shell scripting. Mastering:
- process groups
- signals
- job control
- subshells
- reaping
- PID 1 behavior
โฆis essential for writing safe, predictable, productionโgrade automation.