The wait command in Bash is a powerful tool for managing shell script processes. It is primarily used to pause the execution of a script until the specified background process has finished. This command is handy in scripts that initiate multiple background jobs and need to synchronize their completion before proceeding with further tasks. The wait command can be applied to individual process IDs (PIDs) or to wait for all background processes initiated by the current shell session. By using wait, you can ensure that your script only moves forward when specific tasks are fully completed, making your automation processes more reliable and efficient.
This guide will provide practical examples of using the wait command in various scenarios, helping you understand how to effectively manage background processes in your Bash scripts.
Understanding the Bash wait Command
The wait command in Bash is a built-in function that halts the execution of the current shell until the specified jobs have finished. It then returns the exit status of the command for which it was waiting. This command plays a crucial role in the shell execution environment, and as such, it is built into most shells.
The general syntax of the wait command is as follows:
wait [ID]
In this context, ID represents the process or job ID. If no ID is specified, the wait command will pause until all child background jobs have finished. The wait command returns the exit status of the last command it waited for.
For instance, to pause for a background process with PID 7654, you would use:
wait 7654
If multiple processes are specified, the wait command will pause until they have finished.
Jobs are specified using the job specification (jobspec), which refers to the processes that make up the job. A jobspec begins with a percentage symbol followed by the job number (%n). Here is an example:
rsync -a /home /tmp/home &
This command runs in the background. The shell job ID (enclosed in brackets) and process ID will be displayed on your terminal. To pause for the job, run the wait command followed by the job specification:
wait %2
Utilizing the -n Option with bash wait Command
The -n option allows the wait command to pause only for a single job from the given PIDs or jobspecs to complete and returns its exit status. If no arguments are provided, wait -n waits for any background job to complete and return the job exit status.
wait -n 45432 54346 76573
In the example above, wait -n only prints the return status of the job that exits first; it doesn’t show the job’s PID. If you want to get the job PID or jobspec for which the exit status is returned, use the -p
option to assign it to a variable:
wait -p job_id -n 45432 54346 76573
The -p option was introduced in Bash 5.1. Using an older Bash version will result in an “invalid option” error.
Exploring the -f Option with bash wait Command
The -f option instructs waiting to pause for each PID or jobspec to terminate before returning its exit code rather than returning when the job status is changed. This option is only valid when job control is enabled, which is enabled by default only for interactive prompts.
Practical Examples of the wait Command
The wait command is typically used in shell scripts that spawn child processes that execute in parallel. To illustrate how the command works, let’s create the following script:
#!/bin/bash
sleep 30 &
process_id=$!
echo "PID: $process_id"
wait $process_id
echo "Exit status: $?"
Let’s break down the code line by line:
- The first line, shebang, tells the operating system which interpreter to use to parse the rest of the file.
- We are using the sleep command to emulate a time-consuming background process.
- $! is an internal Bash variable that stores the PID of the last job run in the background. In this example, that is the PID of the sleepcommand. We’re storing the PID in a variable (process_id).
- The PID number is printed.
- The PID is passed to the wait command that pauses until the sleep command completes.
- The exit status of the wait command is printed. $? is an internal Bash variable that holds the exit status of the last command executed.
If you run the script, it will print something like this:
PID: 36353
Exit status: 0
Here’s an example using the -n option:
#!/bin/bash
sleep 3 &
sleep 30 &
sleep 5 &
wait -n
echo "First job completed."
wait
echo "All jobs completed."
When the script is executed, it spawns 3 background processes. wait -n pauses until the first job is completed and the echo statement is printed. wait pauses for all child background jobs to complete.
First job completed.
All jobs completed.
The last example explains the -f option. Open the terminal and run:
sleep 3600 &
[1] 46671
wait 46671
Open another terminal and stop the process with the kill command:
kill -STOP 46671
Once the process status changes, the wait command will be completed, and the process exit code will be returned.
Now, repeat the same steps, but this time use wait -f $pid:
sleep 3600 &
wait -f 46671
Stop the process from the other terminal:
kill -STOP 46671
This time, the wait command will not be complete. It will run until the sleep process terminates.
Advanced Usage of the wait Command
The wait command becomes particularly useful when managing multiple processes in a script. It allows you to control the execution flow and ensure that specific processes have been completed before others begin. Let’s delve into some more complex examples to illustrate this.
Bash wait for Multiple Processes
Consider a scenario where multiple processes run in the background, and you must act only after completing them. Here’s how you can use the wait command to achieve this:
#!/bin/bash
echo "Starting process 1..."
sleep 10 &
pid1=$!
echo "Starting process 2..."
sleep 15 &
pid2=$!
echo "Starting process 3..."
sleep 20 &
pid3=$!
echo "Waiting for processes to complete..."
wait $pid1 $pid2 $pid3
echo "All processes completed."
This script starts three background processes that sleep for 10, 15, and 20 seconds, respectively. We store each process’s PID in a variable. Then, we use the wait command with all three PIDs as arguments. The script will pause at the wait command until all three processes have been completed.
Using Bash wait with a Loop
You can also use wait with a loop to manage multiple processes. Here’s an example:
#!/bin/bash
for i in {1..5}
do
echo "Starting process $i..."
sleep $i &
pids[${i}]=$!
done
echo "Waiting for processes to complete..."
for pid in ${pids[*]}; do
wait $pid
done
echo "All processes completed."
In this script, we’re starting five background processes within a loop. Each process sleeps for several seconds equal to its index in the loop. We store each process’s PID in an array. After starting all the processes, we loop through the array and use the wait command to pause each process individually. The script will pause at each wait command until the corresponding process has been completed.
Conclusion
The wait command in Bash is essential for synchronizing background processes within your scripts. By understanding how to use wait, you can control the flow of your script more precisely, ensuring that tasks are completed in the desired order. Whether you’re dealing with multiple background jobs or must ensure a specific process finishes before proceeding, the wait command can help you achieve more reliable and predictable script behavior. Consider integrating wait into your scripts to enhance process management and improve overall script efficiency.