Gemini on Question 14, Sep 25
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 handle this in Bash is by using the trap command combined with the EXIT pseudo-signal.
Using EXIT is crucial because it fires regardless of how the script dies—whether it reaches the end normally, encounters a fatal error (set -e), or receives a termination signal (like SIGINT/Ctrl+C or SIGTERM).
Here are the best approaches depending on your specific needs:
1. The Standard Way: Killing Direct Children
If your script spawns background processes directly (using &), you can use jobs -p to get their PIDs and kill them when the script exits.
#!/bin/bash
# Define the cleanup function
cleanup() {
# Get all background PIDs spawned by this shell
local pids=$(jobs -p)
if [[ -n "$pids" ]]; then
echo "Purging orphaned children..."
# Send SIGTERM to all children; suppress errors if they already died
kill $pids 2>/dev/null
fi
}
# Trap the EXIT pseudo-signal
trap cleanup EXIT
# --- Your script logic here ---
sleep 100 &
sleep 200 &
echo "Doing work. Press Ctrl+C to test..."
wait2. The Deep Way: Killing Children and Grandchildren
The limitation of jobs -p (and pkill -P $$) is that they only kill direct children. If your background process spawns its own children (grandchildren of your script), they will be orphaned.
To kill the entire process tree, you can send a signal to the script's Process Group by using kill 0.
#!/bin/bash
cleanup() {
echo "Purging entire process group..."
# 'trap - EXIT' prevents an infinite loop if kill 0 triggers the trap again
trap - EXIT
# Send SIGTERM to all processes in the current process group
kill 0
}
trap cleanup EXIT
# --- Your script logic here ---
# Even if this script spawns children that spawn children,
# 'kill 0' will wipe them all out.
./some_deep_script.sh &
waitNote: Be careful with kill 0 if you are source-ing this script in an interactive terminal, as it will kill your terminal session. It is completely safe for standalone executable scripts.
3. The pkill Alternative
If you prefer relying on process IDs rather than Bash's job control, you can use pkill targeting the Parent PID ($$ is the PID of the current script).
#!/bin/bash trap 'pkill -P $$' EXIT # ... spawn processes ...
Pro-Tips for Production Scripts
- •Graceful vs. Forceful:
killsendsSIGTERMby default. If your children might hang and ignoreSIGTERM, you can escalate toSIGKILL(kill -9):
```bash
cleanup() {
local pids=$(jobs -p)
if [[ -n "$pids" ]]; then
kill $pids 2>/dev/null # Ask nicely
sleep 1
kill -9 $pids 2>/dev/null # Force kill if they didn't listen
fi
}
``` - •Systemd: If you are writing this script to run as a long-running service/daemon on Linux, don't do this in bash. Let
systemdhandle it. Systemd puts the service in a Control Group (cgroup) and natively kills all children, grandchildren, and rogue processes when the parent service stops, with zero bash scripting required (KillMode=control-groupis the default).
Exact recordShowHideThe model id, the run, the verbatim text with line numbers and its full sha256
- Scored
- answered
- Received
- 2026-09-25 09:07:20 UTC
- Run
- 20260925T090007Z-f08d1f
- Served by
- Google · HTTP 200 · finish stop
- Size
- 3,210 characters · 2,530 tokens out incl. hidden reasoning · 21.3 s
End of response · 87 lines · 3,210 characters · sha256 fa99a8755e8c8c0aa6e3dad2a35cc96dd899778b8c97393070ef988367e27e69