Gemini on Question 14, Sep 22
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 tied to the EXIT pseudo-signal.
However, the exact command you use inside the trap depends on whether you just have direct child processes, or a deep tree of grandchildren processes.
Here are the three standard approaches, from simplest to most robust.
Method 1: The standard Bash way (Direct Children)
If your script spawns background tasks directly and you want them to die when the script exits, you can kill all active background jobs using jobs -p.
#!/bin/bash # Set a trap to kill all background jobs when the script exits trap 'pids=$(jobs -p); [ -n "$pids" ] && kill $pids 2>/dev/null' EXIT echo "Starting background workers..." sleep 100 & sleep 200 & echo "Doing some work in the parent..." sleep 2 # When the script ends naturally (or via Ctrl+C/SIGTERM), # the trap executes and kills the sleep processes.
Why this is good: It is very clean. It only kills processes explicitly started in the background by this specific shell script.
Limitation: It will not kill "grandchildren" (if your background process spawns its own background processes).
Method 2: The Process Group way (Grandchildren)
If your child processes spawn their own children, Method 1 won't be enough. You need to kill the entire process group. In Bash, sending a signal to PID 0 sends it to the current process group.
#!/bin/bash # Kill the entire process group on exit trap 'trap - TERM; kill 0' EXIT echo "Starting deep process tree..." ( sleep 100 & sleep 100 ) & wait
Why this is good: It mercilessly wipes out the script and every descendant process spawned by it.
Limitation: If your script was not started in its own process group (for example, if it was source'd in a terminal instead of executed), kill 0 might kill your terminal session.
Method 3: Explicit PID tracking (Granular Control)
If you only want to kill specific children and leave others running, you should track their Process IDs (PIDs) in an array.
#!/bin/bash
# Array to hold PIDs
declare -a CHILD_PIDS
# Trap to kill only the tracked PIDs
trap 'for pid in "${CHILD_PIDS[@]}"; do kill "$pid" 2>/dev/null; done' EXIT
sleep 100 &
CHILD_PIDS+=($!) # $! is the PID of the last background command
sleep 200 &
CHILD_PIDS+=($!)
echo "Tracked PIDs: ${CHILD_PIDS[@]}"
wait⚠️ The Fatal Flaw of Bash Scripts (kill -9)
None of the above methods will work if your script is killed with SIGKILL (kill -9) or if the Linux OOM (Out Of Memory) killer terminates your script.
SIGKILL cannot be trapped. If this happens, your script dies instantly, the trap doesn't run, and the children are orphaned (re-parented to init / PID 1).
If you are writing a production system where orphans are absolutely unacceptable, pure Bash isn't enough. You must use Linux's prctl (Process Control) to set a "Death Signal". Because Bash can't do this natively, you can use a tiny wrapper to start your bash script:
The Ultimate Linux Fix (using perl or python as a launcher):
Instead of running ./myscript.sh, run it through a one-liner that sets PDEATHSIG (Parent Death Signal):
# Using perl to set PR_SET_PDEATHSIG (1) to SIGTERM (15) perl -e 'require "syscall.ph"; syscall(&SYS_prctl, 1, 15); exec @ARGV;' -- ./myscript.sh
With this setup, the Linux kernel itself guarantees that if the parent dies for any reason (including kill -9), the kernel will immediately send a SIGTERM to the children.
Exact recordShowHideThe model id, the run, the verbatim text with line numbers and its full sha256
- Scored
- answered
- Received
- 2026-09-22 09:07:59 UTC
- Run
- 20260922T090022Z-7ff13b
- Served by
- Google · HTTP 200 · finish stop
- Size
- 3,620 characters · 2,505 tokens out incl. hidden reasoning · 22.7 s
End of response · 91 lines · 3,620 characters · sha256 4dda5dcf56e7d85070c27a1237436d9bae94c57d892bdae594ab02681fc44831