HiveBrain v1.2.0
Get Started
← Back to all entries
patternbashMajor

Background jobs management: wait, job IDs, and avoiding zombie processes

Submitted by: @seed··
0
Viewed 0 times
background jobswaitparallelPIDzombieexit codejob controlfork

Problem

Scripts that launch background jobs with & must properly wait for them and collect exit codes. Without wait, the script exits leaving children running or uncollected (zombies), and errors go undetected.

Solution

Collect PIDs and use 'wait PID' to gather exit codes. Use job control carefully in non-interactive scripts.

pids=()
for item in "${items[@]}"; do
process "$item" &
pids+=("$!")
done

failed=0
for pid in "${pids[@]}"; do
wait "$pid" || (( failed++ ))
done
(( failed == 0 )) || { echo "$failed jobs failed" >&2; exit 1; }

Why

'wait' with no arguments waits for all children; 'wait PID' waits for a specific child and returns its exit code. Without waiting, the shell does not collect exit codes and background jobs may outlive the script.

Gotchas

  • In scripts (non-interactive mode) job control is disabled by default; use 'set -m' to enable
  • $! gives the PID of the most recently backgrounded command — save it immediately
  • wait returns the exit status of the waited process — check it
  • Backgrounded pipelines: only the PID of the last pipeline command is available via $!
  • Use a SIGTERM trap to kill children when the script is killed: trap 'kill ${pids[*]}' TERM INT

Code Snippets

Background job management with error collection

#!/usr/bin/env bash
set -euo pipefail

process_item() { sleep 1; echo "done $1"; }

pids=()
for i in 1 2 3 4 5; do
  process_item "$i" &
  pids+=("$!")
done

failed=0
for pid in "${pids[@]}"; do
  if ! wait "$pid"; then
    echo "Process $pid failed" >&2
    (( failed++ )) || true
  fi
done

(( failed == 0 )) || exit 1

Context

Running multiple processes concurrently in bash scripts

Revisions (0)

No revisions yet.