Gemini on Question 14, Sep 18
I'm writing a bash script to purge orphaned children after the parent dies. What's the idiomatic way?The most idiomatic way to handle this in Bash is to use the trap builtin combined with the pseudo-signal EXIT. This ensures the cleanup code runs regardless of how the script dies (normal completion, an error if using set -e, or a termination signal like SIGINT/Ctrl+C).
Depending on how complex your child processes are, you have three standard approaches:
1. The Safest Way (Immediate Children)
If your script simply spawns a few background tasks (&), you can ask Bash to kill all currently running background jobs associated with the script using jobs -p.
#!/bin/bash
# Define the cleanup function
cleanup() {
# Get all background PIDs and kill them.
# We suppress errors (2>/dev/null) in case a child already died naturally.
local pids=$(jobs -p)
if [[ -n "$pids" ]]; then
kill $pids 2>/dev/null
fi
}
# Trap the EXIT pseudo-signal, which catches normal exits, errors, and Ctrl+C
trap cleanup EXIT
# --- Your script logic here ---
sleep 100 &
sleep 200 &
echo "Doing some work. Press Ctrl+C to test..."
sleep 10Note: This only kills immediate children. If your background process spawns its own children, those grandchildren will still be orphaned.
2. The Aggressive Way (Process Groups / Deep Trees)
If your background processes spawn their own child processes (e.g., your script calls make, which calls gcc), jobs -p won't be enough. You need to kill the entire Process Group.
Sending a signal to 0 sends it to all processes in the current process group.
#!/bin/bash # Kill all processes in the current process group trap 'trap - TERM; kill 0 2>/dev/null' EXIT # --- Your script logic here --- # Even if this script spawns a deep tree of processes, they all die. ./some_complex_script.sh & sleep 10
Warning: If you run this script by source-ing it, or run it in a way where it shares the terminal's process group, kill 0 will kill your terminal session too. It is perfectly safe for standard, executable shell scripts run as ./script.sh.
3. The Precise Way (Manual Tracking)
If your script spawns both background jobs that should be killed and background jobs that should survive the script, you must track the Process IDs (PIDs) manually using $! (the PID of the last backgrounded process).
#!/bin/bash
# Array to store our children
CHILD_PIDS=()
cleanup() {
for pid in "${CHILD_PIDS[@]}"; do
# -0 checks if the process exists without sending a real signal
if kill -0 "$pid" 2>/dev/null; then
kill "$pid"
fi
done
}
trap cleanup EXIT
# --- Your script logic here ---
# Start a process we want to kill later
sleep 100 &
CHILD_PIDS+=($!)
# Start another process we want to kill later
sleep 200 &
CHILD_PIDS+=($!)
# Start a process we WANT to orphan/survive
nohup sleep 300 >/dev/null 2>&1 &
sleep 10Summary Recommendation
- •Use Approach 1 (
jobs -p) for 90% of standard bash scripts. It's clean, idiomatic, and safe. - •Use Approach 2 (
kill 0) if you are orchestrating heavy workloads (like starting web servers, databases, or build chains) where preventing rogue orphaned grandchildren is critical.
Exact recordShowHideThe model id, the run, the verbatim text with line numbers and its full sha256
- Scored
- answered
- Received
- 2026-09-18 09:08:05 UTC
- Run
- 20260918T090022Z-92b6f7
- Served by
- Google · HTTP 200 · finish stop
- Size
- 3,215 characters · 2,277 tokens out incl. hidden reasoning · 20.3 s
End of response · 90 lines · 3,215 characters · sha256 d8d4e5107d1a1e9dfac4af400f0686a13cfcc746945cbae123546b4522ac4e41