Gemini on Question 14, Sep 19
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 pure Bash is to use the trap command combined with the EXIT pseudo-signal.
However, there are a few different ways to target the children depending on your exact needs. Here is the breakdown from the most standard approach to the most bulletproof.
1. The Standard Idiom: trap + jobs -p
This is the safest and most idiomatic pure-Bash method. It asks Bash for the PIDs of all background jobs currently running under this specific script and kills them. It prevents collateral damage to other processes.
#!/bin/bash
# Define the cleanup function
cleanup() {
# Get PIDs of all background jobs started by this script
local pids=$(jobs -p)
if [[ -n "$pids" ]]; then
# Send SIGTERM to all children; suppress errors if they already died
kill $pids 2>/dev/null
fi
}
# Trap the EXIT signal
trap cleanup EXIT
# --- Your script logic goes here ---
echo "Starting background workers..."
sleep 100 &
sleep 200 &
# Wait for children (or do other work)
waitWhy EXIT? Trapping EXIT ensures the cleanup runs whether the script finishes normally, errors out (e.g., set -e), or is terminated gracefully (like with Ctrl+C or SIGTERM).
2. The Selective Idiom: Tracking Specific PIDs
If your script runs some background tasks that should be killed, but others that should stay alive (like a detached daemon), you should explicitly track the PIDs in an array.
#!/bin/bash
# Array to hold PIDs we want to kill later
declare -a CHILDPIDS=()
cleanup() {
for pid in "${CHILDPIDS[@]}"; do
kill "$pid" 2>/dev/null
done
}
trap cleanup EXIT
# Start a worker we WANT to kill on exit
sleep 100 &
CHILDPIDS+=($!) # $! is the PID of the last backgrounded process
# Start a worker we want to SURVIVE
nohup sleep 500 >/dev/null 2>&1 &
wait "${CHILDPIDS[@]}"3. The "Nuke it all" Idiom: Process Groups (kill 0)
If your children spawn their own children (grandchildren of your script), jobs -p won't catch the grandchildren. To kill the entire process tree spawned by your script, you send a signal to the whole process group using kill 0.
Warning: This will kill the process group your script belongs to. If you ran this script from an interactive shell without job control, it might kill your terminal session.
To do this safely, you should force the script into its own process group by enabling monitor mode (set -m).
#!/bin/bash
set -m # Enable job control so background jobs get their own process group
cleanup() {
# Send SIGTERM to the entire process group
# We trap it first so the script doesn't kill itself before finishing cleanup
trap '' TERM
kill 0 2>/dev/null
}
trap cleanup EXIT
sleep 100 &
bash -c 'sleep 200' & # A child that spawns a grandchild
waitThe Big Caveat: SIGKILL (kill -9)
No bash trap can catch SIGKILL (kill -9) or an Out-Of-Memory (OOM) termination. If your script is killed by SIGKILL, the trap will not run, and your children will be orphaned.
If you absolutely must guarantee that children die even if the parent is kill -9'd, Bash alone cannot do it. You must rely on the Linux kernel (specifically prctl with PR_SET_PDEATHSIG).
The easiest way to utilize this in a bash environment is to wrap your script in a tool designed for it, such as systemd-run or a tiny python/perl wrapper:
# Using systemd to run a scope. # If the scope dies, all children die automatically. systemd-run --user --scope ./your_script.sh
Exact recordShowHideThe model id, the run, the verbatim text with line numbers and its full sha256
- Scored
- answered
- Received
- 2026-09-19 09:07:05 UTC
- Run
- 20260919T090005Z-86161c
- Served by
- Google · HTTP 200 · finish stop
- Size
- 3,610 characters · 2,841 tokens out incl. hidden reasoning · 24.3 s
End of response · 102 lines · 3,610 characters · sha256 c9967fc8322b1a40f618d8335eff9b25a29f43dd7a14301ca730c677ea251178