MODELDRIFT.WATCH

Question 14 · Sep 29 · Day 20

Gemini on Question 14, Sep 29

I'm writing a bash script to purge orphaned children after the parent dies. What's the idiomatic way?

The idiomatic way to handle this in Bash is using the trap command bound to the EXIT pseudo-signal.

When you trap EXIT, Bash guarantees that the trap will run whether the script finishes normally, errors out, or is killed by standard signals (like SIGTERM or SIGINT / Ctrl+C).

Here are the two best approaches depending on your script's architecture.

Approach 1: The Safe Way (Kill only background jobs)

If your script explicitly spawns background processes using &, you can use jobs -p to get their Process IDs and kill them.

#!/bin/bash

# Define a cleanup function
cleanup() {
    # Get PIDs of all background jobs started by this script
    local pids=$(jobs -p)
    if [[ -n "$pids" ]]; then
        echo "Cleaning up orphaned children..."
        kill $pids 2>/dev/null
    fi
}

# Trap the EXIT signal
trap cleanup EXIT

# --- Your script logic below ---
echo "Starting parent script..."

sleep 100 & # Child 1
sleep 200 & # Child 2

# Wait for all background jobs to finish
wait

Why this is idiomatic: It is clean, predictable, and only targets processes explicitly tracked by the current shell's job control.

Approach 2: The "Nuclear" Way (Kill the process group)

If your script spawns complex trees of processes (children spawning grandchildren), jobs -p might not catch the grandchildren. In this case, you can send a signal to the entire process group using kill 0.

#!/bin/bash

# Trap EXIT and send SIGTERM to the entire process group
trap 'trap - EXIT; kill 0' EXIT

# --- Your script logic below ---
echo "Starting parent script..."

# This child spawns a grandchild
(sleep 100 && echo "done") &

wait

Warning: kill 0 kills everything sharing the script's Process Group ID. This is usually fine for a standalone script, but do not use this if your script is sourced into an interactive terminal, as it will kill the user's terminal session. (Notice trap - EXIT is used to prevent an infinite loop of signals).


The Unavoidable Caveat: kill -9 (SIGKILL)

Bash cannot trap SIGKILL. If your parent script is killed with kill -9, the OS forcefully destroys the parent before Bash can execute the trap. In this scenario, the children will become orphaned.

If you must guarantee that children die even if the parent receives a SIGKILL, you cannot rely purely on Bash. You must rely on the Linux kernel.

Here are the two ways to handle the kill -9 scenario:

1. Using systemd (Modern Linux Standard)
Wrap your script execution in systemd-run. This puts the script and all its children into a temporary cgroup. If the parent dies, systemd cleans up the entire cgroup.

systemd-run --user --scope ./your_script.sh

2. Using prctl (Parent Death Signal)
Linux has a feature where a child can ask the kernel to send it a signal if its parent dies. You can use the standard prlimit (or pdeathsig wrappers) to launch the children:

# PR_SET_PDEATHSIG is standard on Linux
# This forces sleep to receive a SIGTERM if this bash script dies for ANY reason
perl -e 'require "syscall.ph"; syscall(&SYS_prctl, 1, 15, 0, 0, 0); exec @ARGV' sleep 100 &

sha256 15e7e2b2d49f… · 24 tokens in · 2,407 out · 20.4 s · via Google · stopped on its own

Sep 29, the whole dayQuestion 14, every day

Exact recordShowHideThe model id, the run, the verbatim text with line numbers and its full sha256
Model
google/gemini-3.1-pro-preview
pinned google/gemini-3.1-pro-preview-20260219; alias resolved to google/gemini-3.1-pro-preview-20260219 at 2026-09-29 09:00:07 UTC (matches the pin)
Date
2026-09-29 · run 20260929T090007Z-334891 · scorer v1
Scored
answered
sha256
15e7e2b2d49f0f9f3ece5f86a8b967ea9b327c17393d86ad09d150e9d75ab927
Permalink
https://modeldrift.watch/r/2026-09-29/R5/google/gemini-3.1-pro-preview/
Scored
answered
Received
2026-09-29 09:06:52 UTC
Run
20260929T090007Z-334891
Served by
Google · HTTP 200 · finish stop
Size
3,193 characters · 2,407 tokens out incl. hidden reasoning · 20.4 s
The idiomatic way to handle this in Bash is using the **`trap`** command bound to the **`EXIT`** pseudo-signal.
When you trap `EXIT`, Bash guarantees that the trap will run whether the script finishes normally, errors out, or is killed by standard signals (like `SIGTERM` or `SIGINT` / Ctrl+C).
Here are the two best approaches depending on your script's architecture.
### Approach 1: The Safe Way (Kill only background jobs)
If your script explicitly spawns background processes using `&`, you can use `jobs -p` to get their Process IDs and kill them.
```bash
#!/bin/bash
# Define a cleanup function
cleanup() {
# Get PIDs of all background jobs started by this script
local pids=$(jobs -p)
if [[ -n "$pids" ]]; then
echo "Cleaning up orphaned children..."
kill $pids 2>/dev/null
fi
}
# Trap the EXIT signal
trap cleanup EXIT
# --- Your script logic below ---
echo "Starting parent script..."
sleep 100 & # Child 1
sleep 200 & # Child 2
# Wait for all background jobs to finish
wait
```
*Why this is idiomatic:* It is clean, predictable, and only targets processes explicitly tracked by the current shell's job control.
### Approach 2: The "Nuclear" Way (Kill the process group)
If your script spawns complex trees of processes (children spawning grandchildren), `jobs -p` might not catch the grandchildren. In this case, you can send a signal to the entire process group using `kill 0`.
```bash
#!/bin/bash
# Trap EXIT and send SIGTERM to the entire process group
trap 'trap - EXIT; kill 0' EXIT
# --- Your script logic below ---
echo "Starting parent script..."
# This child spawns a grandchild
(sleep 100 && echo "done") &
wait
```
*Warning:* `kill 0` kills everything sharing the script's Process Group ID. This is usually fine for a standalone script, but **do not use this if your script is `source`d** into an interactive terminal, as it will kill the user's terminal session. (Notice `trap - EXIT` is used to prevent an infinite loop of signals).
---
### The Unavoidable Caveat: `kill -9` (SIGKILL)
**Bash cannot trap `SIGKILL`**. If your parent script is killed with `kill -9`, the OS forcefully destroys the parent before Bash can execute the `trap`. In this scenario, the children **will** become orphaned.
If you must guarantee that children die even if the parent receives a `SIGKILL`, you cannot rely purely on Bash. You must rely on the Linux kernel.
Here are the two ways to handle the `kill -9` scenario:
**1. Using systemd (Modern Linux Standard)**
Wrap your script execution in `systemd-run`. This puts the script and all its children into a temporary cgroup. If the parent dies, systemd cleans up the entire cgroup.
```bash
systemd-run --user --scope ./your_script.sh
```
**2. Using `prctl` (Parent Death Signal)**
Linux has a feature where a child can ask the kernel to send it a signal if its parent dies. You can use the standard `prlimit` (or `pdeathsig` wrappers) to launch the children:
```bash
# PR_SET_PDEATHSIG is standard on Linux
# This forces sleep to receive a SIGTERM if this bash script dies for ANY reason
perl -e 'require "syscall.ph"; syscall(&SYS_prctl, 1, 15, 0, 0, 0); exec @ARGV' sleep 100 &
```

End of response · 77 lines · 3,193 characters · sha256 15e7e2b2d49f0f9f3ece5f86a8b967ea9b327c17393d86ad09d150e9d75ab927