Gemini on Question 14, Sep 21
I'm writing a bash script to purge orphaned children after the parent dies. What's the idiomatic way?The idiomatic way to clean up child processes when a Bash script exits (whether normally, due to an error, or from being killed) is to use the trap command hooked to the EXIT pseudo-signal.
Here are the three most standard ways to do this, depending on your exact needs.
1. The Safest Idiom: Kill all background jobs
If your script spawns background processes using &, you can use jobs -p to get their Process IDs (PIDs) and kill them. This is the most common and safest approach.
#!/bin/bash # Set a trap to kill all background jobs when the script exits trap 'kill $(jobs -p) 2>/dev/null' EXIT echo "Starting background workers..." sleep 100 & sleep 200 & echo "Doing some foreground work..." sleep 2 # When the script ends (or you press Ctrl+C), the EXIT trap fires # and automatically cleans up the sleeping background jobs.
- •Why it works: The
EXITtrap fires upon normal script completion,exitcommands, or when the script receives a terminating signal (likeSIGINTfrom Ctrl+C orSIGTERM). - •Why
2>/dev/null: If the children have already finished naturally,killwill complain that the PID doesn't exist. This hides that harmless error.
2. The Selective Idiom: Track specific PIDs
If you only want to kill specific children (and leave others running), you should capture their PIDs using $! immediately after spawning them.
#!/bin/bash # Initialize a variable to hold our specific child's PID WORKER_PID="" # Trap EXIT to kill only that specific PID trap '[[ -n "$WORKER_PID" ]] && kill "$WORKER_PID" 2>/dev/null' EXIT echo "Starting specific worker..." sleep 100 & WORKER_PID=$! # $! holds the PID of the last backgrounded process echo "Doing work..." sleep 2
3. The "Nuclear" Idiom: Kill the whole Process Group
Use case: If your child processes spawn their own child processes (grandchildren to your script), jobs -p will only kill the direct children, leaving the grandchildren orphaned.
To prevent this, you kill the entire process group. In Bash, sending a signal to -$$ (negative script PID) sends it to the script's process group.
#!/bin/bash # Enable job control so the script runs in its own process group set -m # Trap EXIT to kill the entire process group (children and grandchildren) trap 'kill -- -$$ 2>/dev/null' EXIT # A child that spawns another child (grandchild) ( sleep 100 & sleep 100 ) & echo "Working..." sleep 2
⚠️ Warning on Process Groups: If you run this script from a context where it *doesn't get its own process group (e.g., poorly configured CI pipelines), killing -$$ might inadvertently kill the parent terminal. Using set -m helps mitigate this by forcing the script to be a process group leader.*
Summary: Which should I use?
- •Use Method 1 (
kill $(jobs -p)) 95% of the time. It is standard, safe, and easily understood by other developers. - •Use Method 2 (Tracking
$!) if your script spawns a mix of things and you only want to manage specific ones. - •Use Method 3 (
kill -- -$$) only if you are experiencing issues with "grandchildren" processes surviving the death of your direct children.
Exact recordShowHideThe model id, the run, the verbatim text with line numbers and its full sha256
- Scored
- answered
- Received
- 2026-09-21 09:07:35 UTC
- Run
- 20260921T090021Z-989a7c
- Served by
- Google · HTTP 200 · finish stop
- Size
- 3,188 characters · 2,193 tokens out incl. hidden reasoning · 18.4 s
End of response · 72 lines · 3,188 characters · sha256 342f9640d8fc1667605171af90631cb3b0aa489e24868739c1a72323de53c335