Gemini on Question 14, Sep 28
I'm writing a bash script to purge orphaned children after the parent dies. What's the idiomatic way?The most idiomatic and reliable way to prevent orphaned child processes in Bash is to use the trap command hooked to the EXIT pseudo-signal.
When you trap EXIT, Bash guarantees the cleanup code will run whether the script finishes naturally, fails due to an error (like set -e), or receives a standard termination signal (like SIGINT or SIGTERM).
Here are the three most idiomatic ways to do it, depending on your script's complexity.
1. The Cleanest Way: Using jobs (Direct Children)
If your script spawns standard background processes using &, Bash tracks them as "jobs". You can dynamically grab all running background jobs and kill them.
#!/bin/bash # Set the trap to kill all background jobs when the script exits trap 'jobs -p | xargs -r kill' EXIT # Spawn some background children sleep 100 & sleep 200 & echo "Parent doing work..." sleep 5 echo "Parent exiting. Children will be killed."
Note: xargs -r prevents kill from throwing an error if there are no jobs running.
2. The Granular Way: Tracking PIDs (Specific Children)
If you only want to kill specific child processes, or if you are doing complex process management, store the process IDs ($!) in an array.
#!/bin/bash
pids=()
# Trap exit and kill the specific PIDs, suppressing errors if they already died
trap 'kill "${pids[@]}" 2>/dev/null' EXIT
# Spawn children and record their PIDs
sleep 100 &
pids+=($!)
sleep 200 &
pids+=($!)
echo "Doing work..."
sleep 53. The Nuclear Way: Process Groups (Nested Grandchildren)
If your child processes spawn their own children (grandchildren of your script), methods 1 and 2 will leave the grandchildren orphaned. To kill the entire process tree, you must send a signal to the script's Process Group ID (PGID). In Bash, the PGID is usually the same as the script's PID ($$).
#!/bin/bash # 1. Clear the trap so we don't get stuck in a loop # 2. Send SIGTERM to the process group (-$$) trap 'trap - EXIT; kill -TERM -$$ 2>/dev/null' EXIT # A child that spawns a grandchild ( sleep 50; sleep 50 ) & echo "Doing work..." sleep 5
⚠️ The One Unavoidable Caveat: SIGKILL (kill -9)
No script can trap SIGKILL (commonly sent via kill -9). If a user or the OOM-killer ends your parent script with kill -9, the EXIT trap will not run, and the children will become orphans.
If this is a hard constraint (e.g., in writing a bulletproof daemon), you cannot rely on Bash alone. You would need to use a Linux-specific tool like prlimit or systemd (which manages process groups via cgroups and cleans them up automatically regardless of kill -9). But for 99% of Bash scripting, the trap EXIT methods above are exactly what you want.
Exact recordShowHideThe model id, the run, the verbatim text with line numbers and its full sha256
- Scored
- answered
- Received
- 2026-09-28 09:07:05 UTC
- Run
- 20260928T090007Z-07d4be
- Served by
- Google · HTTP 200 · finish stop
- Size
- 2,763 characters · 2,182 tokens out incl. hidden reasoning · 20.0 s
End of response · 67 lines · 2,763 characters · sha256 7e4bb357b2bbf8bc291e385c86e6bd5284f7bb6a2eb0c4127eff15418489b266