Sample Header Ad - 728x90

How to wait for background commands that were executed within a subshell?

5 votes
2 answers
221 views
Given this code:
#!/bin/bash
set -euo pipefail
function someFn() {
  local input_string="$1"
  echo "$input_string start"
  sleep 3
  echo "$input_string end"
}

function blocking() {
  someFn "FOO"
  someFn "BAR"
  someFn "BAZ"
  echo "DONE"
}

function wellBehavedParallel() {
  someFn "FOO" &
  someFn "BAR" &
  someFn "BAZ" &
  wait
  echo "DONE"
}

function subShellMadness() {
  (someFn "FOO" &) &
  (someFn "BAR" &) &
  (someFn "BAZ" &) &
  wait
  echo "DONE"
}

echo "BLOCKING_APPROACH"
blocking

echo "WEL_WORKING_PARALLEL"
wellBehavedParallel

echo "THIS DOES NOT WORK"
subShellMadness
It showcases two expected behaviors and one unexpected. 1. The Blocking one Simple, executes one line, then the next, slow and boring but solid:
BLOCKING_APPROACH
    FOO start
    FOO end
    BAR start
    BAR end
    BAZ start
    BAZ end
    DONE
2. The well-behaved parallel one. All commands & are executed in parallel, the wait waits for all of them to finish, and only then does the main script progress further:
WEL_WORKING_PARALLEL
    FOO start
    BAR start
    BAZ start
    FOO end
    BAR end
    BAZ end
    DONE
2. This is (at least to me) unexpected, but I assume this is "by design" that once I use subshells, I cannot use wait in the main script any more. The jobs are still progressed in parallel, but I have lost all control, the main script even ends, and afterwards output is still dumped on the terminal by the subshells:
THIS DOES NOT WORK
    FOO start
    BAR start
    DONE
    BAZ start
    philipp@DESKTOP-H0QQ2H8:~$ FOO end
    BAR end
    BAZ end
Is there a way from a main script to wait for subshells to finish? I want to avoid PID-collecting solutions (I know that wait accepts PID as a parameter), yet from what I gather getting the right PID in the first place may be prone to race conditions (since $! will represent the last executed command's PID, not necessarily my command), and I fear PID-reusage could also make such an approach prone to unexpected behavior (am I waiting on my original command, or did some other process take my pid? When calling wait, I seemingly have no way of knowing). Is there a best practice in dealing with waiting for subshells that reliably waits for them to finish? (Not using subshells is not an option for me right now.)
Asked by k0pernikus (16551 rep)
Aug 9, 2025, 01:10 PM
Last activity: Aug 10, 2025, 02:02 PM