Gemini on Question 14, Sep 26
I'm writing a bash script to purge orphaned children after the parent dies. What's the idiomatic way?In Bash, the most idiomatic way to clean up child processes when the parent script terminates is to use the trap command hooked to the EXIT pseudo-signal.
Depending on your process tree, there are three main ways to do this.
1. The Standard Way: jobs -p (Best for direct children)
If your script spawns background tasks using &, Bash keeps track of them in its internal jobs list. You can kill them all cleanly using jobs -p.
#!/bin/bash
cleanup() {
echo "Cleaning up..."
# Kill all background jobs spawned by this script
kill $(jobs -p) 2>/dev/null
}
# Trigger the cleanup function when the script exits (normally or via signal)
trap cleanup EXIT
# Example workload
sleep 100 &
sleep 200 &
echo "Doing some work. Press Ctrl+C to exit."
sleep 10- •Pros: Extremely safe. It only targets direct children spawned by this specific script.
- •Cons: It does not kill grandchildren. If your background process spawns its own children, those will become orphaned.
2. The Unix Way: Process Groups (Best for deep process trees)
If your background jobs spawn their own children (grandchildren of your script) and you want to obliterate the entire process tree, you should signal the Process Group.
By default, sending a signal to 0 sends it to the entire process group the script belongs to.
#!/bin/bash
# Ignore SIGTERM in the parent so the script doesn't kill itself before finishing cleanup
trap '' TERM
cleanup() {
echo "Killing entire process group..."
# kill 0 sends SIGTERM to all processes in the current process group
kill 0 2>/dev/null
}
trap cleanup EXIT
# Example workload
./some_script_that_spawns_other_scripts.sh &
sleep 100 &
wait- •Pros: Kills children, grandchildren, and great-grandchildren.
- •Cons: Never
sourcethis script. If you run. ./script.shin your terminal, the terminal shares the process group, andkill 0will close your terminal. Always execute it as./script.sh.
3. The Granular Way: Tracking PIDs (Best for selective killing)
If you only want to kill specific children and leave others running, you should save their Process IDs ($!) into an array immediately after spawning them.
#!/bin/bash
# Array to hold PIDs
declare -a PIDS=()
cleanup() {
echo "Cleaning up specific children..."
for pid in "${PIDS[@]}"; do
# Check if process is still running, then kill it
if kill -0 "$pid" 2>/dev/null; then
kill "$pid"
fi
done
}
trap cleanup EXIT
# Spawn a child we WANT to kill on exit
sleep 100 &
PIDS+=($!)
# Spawn a child we want to SURVIVE the exit
nohup sleep 300 >/dev/null 2>&1 &
wait "${PIDS[@]}"⚠️ The SIGKILL Caveat (Important)
It is crucial to understand that Bash cannot trap SIGKILL (kill -9).
If the user, the system administrator, or the Linux OOM (Out Of Memory) killer sends a SIGKILL to your parent script, the EXIT trap will not run, and your children will be orphaned.
If you absolutely must guarantee children die even if the parent gets SIGKILL, Bash alone isn't enough. You have two options:
- 1.Linux
prctl: Wrap your script in a tool likepdeathor write a tiny C/Python wrapper that setsPR_SET_PDEATHSIG, which tells the kernel to kill children when the parent thread dies. - 2.Systemd: Run your script as a
systemdservice. Systemd manages processes via Control Groups (cgroups) and will flawlessly tear down all orphaned grandchildren when the main service dies.
Exact recordShowHideThe model id, the run, the verbatim text with line numbers and its full sha256
- Scored
- answered
- Received
- 2026-09-26 09:06:47 UTC
- Run
- 20260926T090007Z-89c0b7
- Served by
- Google · HTTP 200 · finish stop
- Size
- 3,576 characters · 2,520 tokens out incl. hidden reasoning · 21.1 s
End of response · 104 lines · 3,576 characters · sha256 daeb2f1b015a8a8c629dc4acd8c77a3cd5671078bd4c4bf7843a2bae63d14398