# Background Jobs, wait and Signals — Bash / Shell Scripting

Source: https://www.skillbyai.com/en/bash/s-processes

> Run work in parallel, wait for it and handle signals.

## Doing several things at once

Ending a command with **`&`** runs it in the **background**; the script continues immediately and **`$!`** holds the background process ID. **`wait`** pauses until background jobs finish: `wait $pid` waits for one and returns its exit status, plain `wait` waits for all, and `wait -n` (Bash 4.3+) returns when any one finishes, which allows simple concurrency limits. Always check statuses: a background job's failure does not stop the script under `set -e` unless you `wait` for it. **Signals** are how processes are told to stop or reload: `SIGTERM` (15, polite stop, the default for `kill`), `SIGINT` (2, Ctrl+C), `SIGHUP` (1, often "reload configuration"), and `SIGKILL` (9, cannot be caught, use as a last resort). Long-running scripts should handle `TERM` and `INT` with traps so they stop child processes cleanly. Use `timeout 30s cmd` to bound how long a command may run.

## Fork, run in parallel, wait

Background jobs run alongside the script, which later waits and collects their exit statuses.

![A main horizontal line splitting into three parallel lines that later rejoin into one, with small status badges at the join.](assets/figures/bash/section-7-map.svg) — Figure 7.1 — Parallel background jobs joined with wait.

## Parallel health checks with a concurrency limit

At most 4 checks run at once, and every failure is counted.

```bash
#!/usr/bin/env bash
set -uo pipefail

check() { timeout 10s curl -fsS "https://$1/health" > /dev/null; }

max_jobs=4 failures=0
mapfile -t hosts < hosts.txt

for host in "${hosts[@]}"; do
    check "$host" &
    while (( $(jobs -rp | wc -l) >= max_jobs )); do
        wait -n || (( failures++ )) || true
    done
done
while (( $(jobs -rp | wc -l) > 0 )); do
    wait -n || (( failures++ )) || true
done

echo "$failures of ${#hosts[@]} hosts failed" >&2
(( failures == 0 ))
```

## Background failures are silent unless you wait

A command started with `&` can fail without anyone noticing. Collect PIDs, `wait` for each and check the status, or the script will report success while half the work failed.

**Quiz:** Which signal cannot be caught or ignored by a process?

- [x] SIGKILL
- [ ] SIGTERM
- [ ] SIGINT
- [ ] SIGHUP

*Answer:* SIGKILL. SIGKILL (9) terminates immediately; it cannot be trapped, which is why it is a last resort.
