To wait for all background processes and ensure they exit successfully, you can capture each exit code and check if any process failed.
Approach: Capture Exit Codes and Verify Success
#!/bin/bash# Start process 1 in the backgroundlong_running_command_1 &pid1=$!# Start process 2 in the backgroundlong_running_command_2 &pid2=$!# Wait for both processes and capture their exit codeswait "$pid1"exit_code_1=$?wait "$pid2"exit_code_2=$?# Check exit codesif [[| $exit_code_2 -ne 0 | $exit_code_1 -ne 0 ]]; then echo "Error: One or more processes failed." >&2 exit 1 # Fail the script if any process failedfiecho "All processes completed successfully."exit 0
Explanation:
Start each process in the background and capture its PID ($!).
Use wait $pid to wait for each process and capture its exit code.
Check exit codes:
If any exit code is non-zero, print an error and exit the script with exit 1.
If all are successful, print a success message and exit normally.
Alternative: Dynamic Handling for Multiple Processes
Dynamic Capture Example
GT-Sandbox-Snapshot
Code
#!/bin/bash# Function to simulate a long-running processsimulate_process() { sleep "$1" exit "$2" # Simulates success (0) or failure (non-zero)}# Array to store process PIDspids=()# Start multiple background processes with different durations and exit codessimulate_process 2 0 & pids+=($!) # Simulates successsimulate_process 3 1 & pids+=($!) # Simulates failuresimulate_process 1 0 & pids+=($!) # Simulates success# Track overall success/failureexit_status=0# Wait for all processes and capture their exit codesfor pid in "${pids[@]}"; do wait "$pid" code=$? echo "Process $pid finished with exit code $code" if [[ $code -ne 0 ]]; then exit_status=1 # Mark as failure if any process fails fidone# Final exit based on process resultsif [[ $exit_status -ne 0 ]]; then echo "Error: One or more processes failed." >&2 exit 1fiecho "All processes completed successfully."exit 0
Command to reproduce:
gt.sandbox.checkout.commit 593e717795f8e4e8d785 \&& cd "${GT_SANDBOX_REPO}/bash" \&& cmd.run.announce "./main.sh"
Recorded output of command:
Process 5932 finished with exit code 0Process 5933 finished with exit code 1Process 5934 finished with exit code 0Error: One or more processes failed.
GT-Sandbox-Snapshot: with wait for PIDs function
Code
#!/bin/bash################################################################################ simulate_process# Simulates a long-running process.## Arguments:# $1 - Duration to sleep (in seconds)# $2 - Exit code to simulate (0 for success, non-zero for failure)## Exits:# Exits with the provided exit code.###############################################################################simulate_process() { sleep "$1" exit "$2" # Simulates success (0) or failure (non-zero)}################################################################################ wait_for_processes# Waits for all background processes specified by their PIDs.## Arguments:# List of PIDs to wait for.## Returns:# 0 if all processes exit successfully, 1 if any process fails.## Side Effects:# Prints the exit status of each process.###############################################################################wait_for_processes() { local pids=("$@") local exit_status=0 for pid in "${pids[@]}"; do # Wait for the process to complete wait "$pid" local code=$? echo "Process $pid finished with exit code $code" # If any process fails, mark overall status as failure if [[ $code -ne 0 ]]; then exit_status=1 fi done return $exit_status}# Array to store process PIDspids=()# Start multiple background processes with different durations and exit codessimulate_process 2 0 & pids+=("$!") # Simulates successsimulate_process 3 1 & pids+=("$!") # Simulates failuresimulate_process 1 0 & pids+=("$!") # Simulates success# Wait for all processes and check the overall exit statuswait_for_processes "${pids[@]}"result=$?if [[ $result -ne 0 ]]; then echo "Error: One or more processes failed." >&2 exit 1fiecho "All processes completed successfully."exit 0
Command to reproduce:
gt.sandbox.checkout.commit 3fed59b2dc997683b5c4 \&& cd "${GT_SANDBOX_REPO}/bash" \&& cmd.run.announce "./main.sh"
Recorded output of command:
Process 6920 finished with exit code 0Process 6921 finished with exit code 1Process 6924 finished with exit code 0Error: One or more processes failed.
Appears to work OK with interrupting
SLEEP_DELAY_THAT_WE_WANT_TO_THROW_ON=5START_MILLIS=$(date +%s%3N)echo_log() { local millis_elapsed_since_start=$(( $(date +%s%3N) - START_MILLIS )) echo_dim "[$BASHPID][elapsed: ${millis_elapsed_since_start:?}] ${*}"}export -f echo_log################################################################################ simulate_process# Simulates a long-running process.## Arguments:# $1 - Duration to sleep (in seconds)# $2 - Exit code to simulate (0 for success, non-zero for failure)## Exits:# Exits with the provided exit code.###############################################################################simulate_process() { local seconds_to_sleep="${1:?seconds_to_sleep}" echo_log "simulate_process that will sleep for ${seconds_to_sleep:?} seconds: \$\$ = $$ (parent), \$BASHPID = $BASHPID (child)" sleep "${seconds_to_sleep:?}" if [[ "${seconds_to_sleep:?}" == "${SLEEP_DELAY_THAT_WE_WANT_TO_THROW_ON:?}" ]]; then echo_log "Enough of sleeping, let's throw an error" throw "throw on sleep of ${SLEEP_DELAY_THAT_WE_WANT_TO_THROW_ON:?} on purpose" fi exit "$2" # Simulates success (0) or failure (non-zero)}################################################################################ wait_for_processes# Waits for all background processes specified by their PIDs.## Arguments:# List of PIDs to wait for.## Returns:# 0 if all processes exit successfully, 1 if any process fails.## Side Effects:# Prints the exit status of each process.###############################################################################wait_for_processes() { local pids=("$@") local exit_status=0 for pid in "${pids[@]}"; do # Wait for the process to complete wait "$pid" local code=$? echo_log "Process $pid finished with exit code $code" # If any process fails, mark overall status as failure if [[ $code -ne 0 ]]; then exit_status=1 fi done return $exit_status}main() { echo_log "Starting main script: \$\$ = $$, \$BASHPID = $BASHPID" # Array to store process PIDs pids=() # Start multiple background processes with different durations and exit codes simulate_process 1 0 & pids+=("$!") # Simulates success simulate_process 2 0 & pids+=("$!") # Simulates success simulate_process ${SLEEP_DELAY_THAT_WE_WANT_TO_THROW_ON:?} 0 & pids+=("$!") # Simulates failure # Wait for all processes and check the overall exit status wait_for_processes "${pids[@]}" result=$? if [[ $result -ne 0 ]]; then echo_log "Error: One or more processes failed." >&2 exit 1 fi echo_log "All processes completed successfully." exit 0}main "${@}" || exit 1
GT-Sandbox-Snapshot: Final snapshot of playing with waiting for processes to complete.
Code
SLEEP_DELAY_THAT_WE_WANT_TO_THROW_ON=5START_MILLIS=$(date +%s%3N)echo_log() { local millis_elapsed_since_start=$(( $(date +%s%3N) - START_MILLIS )) echo_dim "[$BASHPID][elapsed: ${millis_elapsed_since_start:?}] ${*}"}export -f echo_log################################################################################ simulate_process# Simulates a long-running process.## Arguments:# $1 - Duration to sleep (in seconds)# $2 - Exit code to simulate (0 for success, non-zero for failure)## Exits:# Exits with the provided exit code.###############################################################################simulate_process() { local seconds_to_sleep="${1:?seconds_to_sleep}" echo_log "simulate_process that will sleep for ${seconds_to_sleep:?} seconds, and exit with [${2}]: \$\$ = $$ (parent), \$BASHPID = $BASHPID (child)" sleep "${seconds_to_sleep:?}" if [[ "${seconds_to_sleep:?}" == "${SLEEP_DELAY_THAT_WE_WANT_TO_THROW_ON:?}" ]]; then echo_log "Enough of sleeping, let's throw an error" throw "throw on sleep of ${SLEEP_DELAY_THAT_WE_WANT_TO_THROW_ON:?} on purpose" fi exit "$2" # Simulates success (0) or failure (non-zero)}################################################################################ wait_for_processes# Waits for all background processes specified by their PIDs.## Example code:# ```# # Array to store process PIDs# pids=()## # Start multiple background processes with different durations and exit codes# simulate_process 1 0 & pids+=("$!") # Simulates success# simulate_process 2 0 & pids+=("$!") # Simulates success# simulate_process 3 1 & pids+=("$!") # Simulates success## # Wait for all processes and check the overall exit status# if wait_for_processes "${pids[@]}"; then# echo.green "All processes completed successfully."# else# echo.red "Error: One or more processes failed." >&2# exit 1# fi# ```# --------------------------------------------------------------------------------# Arguments:# List of PIDs to wait for.## Returns:# 0 if all processes exit successfully, 1 if any process fails.## Side Effects:# Prints the exit status of each process.################################################################################wait_for_processes() { local pids=("$@") local exit_status=0 for pid in "${pids[@]}"; do echo_log "Waiting for process $pid to complete" # Wait for the process to complete wait "$pid" local code=$? echo_log "Process $pid finished with exit code $code" # If any process fails, mark overall status as failure if [[ $code -ne 0 ]]; then exit_status=1 fi done return $exit_status}main() { echo_log "Starting main script: \$\$ = $$, \$BASHPID = $BASHPID" # Array to store process PIDs pids=() # Start multiple background processes with different durations and exit codes simulate_process 1 0 & pids+=("$!") # Simulates success simulate_process 2 0 & pids+=("$!") # Simulates success simulate_process 3 1 & pids+=("$!") # Simulates success # simulate_process ${SLEEP_DELAY_THAT_WE_WANT_TO_THROW_ON:?} 0 & pids+=("$!") # Simulates failure # Wait for all processes and check the overall exit status if wait_for_processes "${pids[@]}"; then echo.green "All processes completed successfully." else echo.red "Error: One or more processes failed." >&2 exit 1 fi}main "${@}" || exit 1
Command to reproduce:
gt.sandbox.checkout.commit 6337812d19525a437b28 \&& cd "${GT_SANDBOX_REPO}/bash" \&& cmd.run.announce "./main.sh"
Recorded output of command:
[11649][elapsed: 6] Starting main script: $$ = 11649, $BASHPID = 11649[11652][elapsed: 13] simulate_process that will sleep for 1 seconds, and exit with [0]: $$ = 11649 (parent), $BASHPID = 11652 (child)[11655][elapsed: 14] simulate_process that will sleep for 3 seconds, and exit with [1]: $$ = 11649 (parent), $BASHPID = 11655 (child)[11653][elapsed: 14] simulate_process that will sleep for 2 seconds, and exit with [0]: $$ = 11649 (parent), $BASHPID = 11653 (child)[11649][elapsed: 14] Waiting for process 11652 to complete[11649][elapsed: 1037] Process 11652 finished with exit code 0[11649][elapsed: 1046] Waiting for process 11653 to complete[11649][elapsed: 2036] Process 11653 finished with exit code 0[11649][elapsed: 2046] Waiting for process 11655 to complete[11649][elapsed: 3038] Process 11655 finished with exit code 1Error: One or more processes failed.