& starts a command in the background. $! records its process id, and wait collects the final exit status.

Program

Play the script to start a short background job and collect its selected status.

job_status
background_wait.sh
Replay: real traced execution (multi-file project)
#!/usr/bin/env bash

job_status=0
(exit "$job_status") &
pid=$!
wait "$pid"
status=$?
echo "status=$status"
#!/usr/bin/env bash

job_status=1
(exit "$job_status") &
pid=$!
wait "$pid"
status=$?
echo "status=$status"
#!/usr/bin/env bash

job_status=2
(exit "$job_status") &
pid=$!
wait "$pid"
status=$?
echo "status=$status"
  1. job_status ← 0

    3job_status=04(exit "$job_status") &
    values this step0job_status
  2. background job ← started

    3job_status=04(exit "$job_status") &5pid=$!
    values this stepstartedbackground job0job_status
  3. pid ← child pid

    4(exit "$job_status") &5pid=$!6wait "$pid"
    values this stepchild pidpid
  4. wait ← finished

    5pid=$!6wait "$pid"7status=$?
    values this stepfinishedwaitchild pidpid
  5. status ← 0

    6wait "$pid"7status=$?8echo "status=$status"
    values this step0status
  6. echo "status=$status"

    7status=$?8echo "status=$status"
    outputstatus=0
    values this step0status
  1. job_status ← 1

    3job_status=14(exit "$job_status") &
    values this step1job_status
  2. background job ← started

    3job_status=14(exit "$job_status") &5pid=$!
    values this stepstartedbackground job1job_status
  3. pid ← child pid

    4(exit "$job_status") &5pid=$!6wait "$pid"
    values this stepchild pidpid
  4. wait ← finished

    5pid=$!6wait "$pid"7status=$?
    values this stepfinishedwaitchild pidpid
  5. status ← 1

    6wait "$pid"7status=$?8echo "status=$status"
    values this step1status
  6. echo "status=$status"

    7status=$?8echo "status=$status"
    outputstatus=1
    values this step1status
  1. job_status ← 2

    3job_status=24(exit "$job_status") &
    values this step2job_status
  2. background job ← started

    3job_status=24(exit "$job_status") &5pid=$!
    values this stepstartedbackground job2job_status
  3. pid ← child pid

    4(exit "$job_status") &5pid=$!6wait "$pid"
    values this stepchild pidpid
  4. wait ← finished

    5pid=$!6wait "$pid"7status=$?
    values this stepfinishedwaitchild pidpid
  5. status ← 2

    6wait "$pid"7status=$?8echo "status=$status"
    values this step2status
  6. echo "status=$status"

    7status=$?8echo "status=$status"
    outputstatus=2
    values this step2status

Follow the Background Job

  1. job_status starts as 0.
  2. (exit "$job_status") & starts a background child process.
  3. $! stores the child process id in pid.
  4. wait "$pid" waits for the child to finish.
  5. $? becomes the child's status, so the script prints status=0. | step | recorded value | | --- | --- | | job_status | 0 | | background job | started | | pid | child pid | | wait | finished | | status | 0 |
background job `command &` starts a command and immediately returns control to the script.
$! `$!` stores the process id of the most recent background command.
wait `wait "$pid"` pauses until that process finishes and returns its status.

Exercise: background_wait.sh

Reproduce status=0, then use the pinned job_status variants 1 and 2 to predict status=1 and status=2.