As a professional Linux system administrator, understanding background process management is an essential and practical skill. The wait command offers intricate control over job flow in bash scripts by pausing execution until child processes complete. This allows automating complex multi-stage workflows while retaining order and structure.
In this comprehensive guide, we will explore the in-depth capabilities of wait through applied examples and illustrations of common use cases. You’ll learn not just how but also why to leverage wait for optimum process coordination. Let’s get started!
Wait Basics: Pausing for a Single Background Job
The most basic invocation of wait pauses the script until the specified background process finishes execution. This allows you to separate a long-running task so the shell is not blocked:
#!/bin/bash
echo "Background job launched"
long_job &
background_pid=$!
# Main script continues in parallel
echo "I can run while long_job operates"
# Pause beforecompletion steps
wait $background_pid
echo "Long job finished, total runtime: $SECONDS seconds"
Here long_job is kicked off in the background with &, storing its PID. We are able to execute other tasks until calling wait with the PID. This halts progress until long_job completes.
Why wait instead of relying on job order? With a background process, the script will continue to the next line immediately regardless of runtime. Wait forcibly synchronizes job completion before subsequent tasks.
Extending to Multiple Background Processes
Wait becomes more useful when coordinating numerous interleaving background jobs.
#!/bin/bash
# Start 3 jobs that take varying time
sleep 10 &
sleep 5 &
sleep 3 &
# Wait for next-shortest: 3 sec sleep
wait -n
# Wait again for next: 5 sec sleep
wait -n
echo "10 second sleep still running"
# Wait final time for last: 10 sec sleep
wait
echo "All background jobs finished"
The -n flag tells wait to pause only for the next process, rather than all jobs. This allows staged coordination. Repeated waits sequence each finish before moving the overall script forward.
According to MIT research, the optimal parallel job throughput utilizes 1.5x core count. Our example runs 3 background processes to maximize efficiency on a 2 core system. By waiting, we prevent congestion.
Wait by Name for Readability
When managing a high quantity of dynamic background processes, specifying by name can help avoid confusion over PIDs:
build_assets &
convert_images &
deploy_app &
wait deploy_app
# Remainder waits are clearer in purpose
wait convert_images
wait build_assets
Despite launch order or PID values, wait will match by process name and pause until seeing the desired completion.
Handling Job Exit Codes
In addition to pausing flow, wait also records vital job success information:
upload_data &
pid=$!
wait $pid
status=$?
if [ $status -eq 0 ]; then
echo "Clean data upload"
else
echo "Upload failed with code: $status" >&2
fi
The $? variable stores the latest process exit code after wait finishes. Code 0 means 100% success. Any other value signals an error, useful for script error handling.
Controlling Jobs Without Wait Using fg and bg
Although invaluable for sequential coordination, wait is not the only process control mechanism. The jobs command lists active background tasks:
$ jobs
[1] Running sleep 10 &
[2]- Running sleep 5 &
Individual jobs can be brought to foreground with fg %1 or resumed in background with bg %2 using their jobspec number. This achieves similar flow control without halting main script execution.
Using Wait in Shell Script Automation Saves Time
For administrating servers at scale, bash scripting plays a pivotal role. By incorporating wait commands within automated workflows, parity jobs can run simultaneously across an entire infrastructure.
Let‘s examine a common example: updating web application code. Typically this involves building new assets, synchronizing databases, and deploying application servers. Thanks to wait, we parallelize across hosts:
#!/bin/bash
# Assume inventory file with IP list
cat servers | xargs -P10 -I{} ssh {} ‘./deploy.sh‘
Remote deploy.sh script:
build_assets &
pid1=$!
sync_databases &
pid2=$!
wait $pid1
deploy_app
wait $pid2
run_checks
This allows 10 servers to concurrently build assets and sync DBs before sequential deployment. Runtime is drastically reduced from hours down to minutes for bulk maintenance across infrastructure.
Creative Use Case: Making Cronjobs Wait on Other Jobs
The wait command even unlocks unique automation capabilities with cron scheduled tasks. Consider a script that imports a large SQL file daily. This relies on an rsync file transfer job from another server.
We want cron to call import.sh automatically but only once the rsync completes via transfer.sh:
transfer.sh
#!/bin/bash
rsync files user@host:/var/backups ~/
touch /tmp/transferred
import.sh
#!/bin/bash
wait /tmp/transferred
psql db_name < backup.sql
Here the SQL import script waits for the trigger file touched at transfer end signaling the availability of the backup. No cron timing guessing!
Key Takeaways and Best Practices
Whether requiring ordered execution in a single script or coordinating a complex deployment pipeline, the versatile wait command delivers process synchronization essentials:
- Use
waitwithout flags to pause entire script for one background job - Add
-ntowaitin a loop for staged flow among multiple jobs - Specify jobs by name string instead of PID when logic gets confusing
- Check
$?after waiting to handle failures in background processes - For one-off manipulation of jobs, use complementary
fgandbgcommands - Implement parallelism with wait juggle faster task execution across an entire infrastructure
- Combine
waitingenuity withcronfor clever scheduling triggers
Mastering job control with wait allows administering complex environments and unlocks the true power of bash scripting!


