Both your example and the accepted answer are overly complicated, why do you not only use timeout since that is exactly its use case? The timeout command even has an inbuilt option (-k) to send SIGKILL after sending the initial signal to terminate the command (SIGTERM by default) if the command is still running after sending the initial signal (see man timeout).

If the script doesn't necessarily require to wait and resume control flow after waiting it's simply a matter of

timeout -k 60s 60s app1 &
timeout -k 60s 60s app2 &
# [...]

If it does, however, that's just as easy by saving the timeout PIDs instead:

pids=()
timeout -k 60s 60s app1 &
pids+=($!)
timeout -k 60s 60s app2 &
pids+=($!)
wait "${pids[@]}"
# [...]

E.g.

$ cat t.sh
#!/bin/bash

echo "$(date +%H:%M:%S): start"
pids=()
timeout 10 bash -c 'sleep 5; echo "$(date +%H:%M:%S): job 1 terminated successfully"' &
pids+=($!)
timeout 2 bash -c 'sleep 5; echo "$(date +%H:%M:%S): job 2 terminated successfully"' &
pids+=($!)
wait "${pids[@]}"
echo "$(date +%H:%M:%S): done waiting. both jobs terminated on their own or via timeout; resuming script"

.

$ ./t.sh
08:59:42: start
08:59:47: job 1 terminated successfully
08:59:47: done waiting. both jobs terminated on their own or via timeout; resuming script
Answer from Adrian Frühwirth on Stack Overflow
🌐
Linuxize
linuxize.com › home › bash › bash wait command
Bash wait Command | Linuxize
January 30, 2026 - The wait command waits for one or more background jobs to complete and returns the exit status of the waited-for command. Since it affects the current shell execution environment, wait is implemented as a built-in command in most shells.
Top answer
1 of 12
79

Both your example and the accepted answer are overly complicated, why do you not only use timeout since that is exactly its use case? The timeout command even has an inbuilt option (-k) to send SIGKILL after sending the initial signal to terminate the command (SIGTERM by default) if the command is still running after sending the initial signal (see man timeout).

If the script doesn't necessarily require to wait and resume control flow after waiting it's simply a matter of

timeout -k 60s 60s app1 &
timeout -k 60s 60s app2 &
# [...]

If it does, however, that's just as easy by saving the timeout PIDs instead:

pids=()
timeout -k 60s 60s app1 &
pids+=($!)
timeout -k 60s 60s app2 &
pids+=($!)
wait "${pids[@]}"
# [...]

E.g.

$ cat t.sh
#!/bin/bash

echo "$(date +%H:%M:%S): start"
pids=()
timeout 10 bash -c 'sleep 5; echo "$(date +%H:%M:%S): job 1 terminated successfully"' &
pids+=($!)
timeout 2 bash -c 'sleep 5; echo "$(date +%H:%M:%S): job 2 terminated successfully"' &
pids+=($!)
wait "${pids[@]}"
echo "$(date +%H:%M:%S): done waiting. both jobs terminated on their own or via timeout; resuming script"

.

$ ./t.sh
08:59:42: start
08:59:47: job 1 terminated successfully
08:59:47: done waiting. both jobs terminated on their own or via timeout; resuming script
2 of 12
28

Write the PIDs to files and start the apps like this:

pidFile=...
( app ; rm $pidFile ; ) &
pid=$!
echo pidFile
( sleep 60 ; if [[ -e $pidFile ]]; then killChildrenOf $pid ; fi ; ) &
killerPid=$!

wait $pid
kill $killerPid

That would create another process that sleeps for the timeout and kills the process if it hasn't completed so far.

If the process completes faster, the PID file is deleted and the killer process is terminated.

killChildrenOf is a script that fetches all processes and kills all children of a certain PID. See the answers of this question for different ways to implement this functionality: Best way to kill all child processes

If you want to step outside of BASH, you could write PIDs and timeouts into a directory and watch that directory. Every minute or so, read the entries and check which processes are still around and whether they have timed out.

EDIT If you want to know whether the process has died successfully, you can use kill -0 $pid

EDIT2 Or you can try process groups. kevinarpe said: To get PGID for a PID(146322):

ps -fjww -p 146322 | tail -n 1 | awk '{ print $4 }'

In my case: 145974. Then PGID can be used with a special option of kill to terminate all processes in a group: kill -- -145974

Discussions

bash - Difference between wait and sleep - Stack Overflow
IMHO it is wait %1 %2 or wait 27408 27409 or simply wait if there is no other background process. In this case you are trying to wait for PID 1 (init) and PID 2 ([migration/0] on my Linux), but you will get error message, like: -bash: wait: pid 1 is not a child of this shell and returns the ... More on stackoverflow.com
🌐 stackoverflow.com
background process - Bash wait for all subprocesses of script - Unix & Linux Stack Exchange
I have a script with for i in 1 2 3 4; do do_something $i & done And when I call it, it terminates before all do_something terminated. I found this question with many different answers. ... More on unix.stackexchange.com
🌐 unix.stackexchange.com
September 12, 2019
bash - Significance of `[...] & wait $!` - Unix & Linux Stack Exchange
What is the significance of the bash pattern [...] & wait $!? For example: curl -LsS $AZP_AGENT_PACKAGE_LATEST_URL | tar -xz & wait $! I understand this as: The & instructs bash to ru... More on unix.stackexchange.com
🌐 unix.stackexchange.com
June 7, 2022
How can I make WAIT to run properly in this case?
Instead of this:- _PID=$(pidof pop-upgrade) use PID=$ _PID=$! edited, to acknowledge a correction from u/PageFault . It's holidays and drink may have been involved :-) More on reddit.com
🌐 r/bash
14
9
December 29, 2022
People also ask

Does the Bash wait command work in sh and zsh?
The basic wait command (with no flags) works in sh, bash, and zsh. However, the -n flag requires Bash 4.3 or newer, and -p requires Bash 5.1. Zsh supports wait -n natively but does not support -p. POSIX sh only supports the basic wait syntax without any flags.
🌐
linuxcapable.com
linuxcapable.com › home › linux commands › bash wait command with examples
Bash wait Command with Examples - LinuxCapable
How do I add a timeout to the Bash wait command?
The wait command has no built-in timeout option. To implement a timeout, run a background sleep as a deadline and use wait -n to return when either the target process or the timer finishes first. Check which PID completed using the -p flag (Bash 5.1+) to determine whether the process finished or the timeout expired.
🌐
linuxcapable.com
linuxcapable.com › home › linux commands › bash wait command with examples
Bash wait Command with Examples - LinuxCapable
What is the difference between wait and sleep in Bash?
The wait command pauses until a background process finishes and returns its exit status. The sleep command pauses for a fixed number of seconds regardless of other processes. Use wait to synchronize with background jobs, and sleep when you need a timed delay.
🌐
linuxcapable.com
linuxcapable.com › home › linux commands › bash wait command with examples
Bash wait Command with Examples - LinuxCapable
🌐
PhoenixNAP
phoenixnap.com › home › kb › sysadmin › bash wait command with examples
Bash wait Command with Examples
December 11, 2025 - For example, wait %1 pauses for process 1 (sleep 10) to complete. 1. When working with multiple processes, use the PID to identify a process. The example script below displays a single use case: #!/bin/bash echo "Process 1 lasts for 2s" && sleep 2 & PID=$! echo "Process 2 lasts for 3s" && sleep 3 & echo "Current time $(date +%T)" wait $PID echo "Process 1 ended at time $(date +%T) with exit status $?" wait $! echo "Process 2 ended at time $(date +%T) with exit status $?"
🌐
Linux Man Pages
man7.org › linux › man-pages › man1 › wait.1p.html
wait(1p) - Linux manual page
When an asynchronous list (see Section 2.9.3.1, Examples) is started by the shell, the process ID of the last command in each element of the asynchronous list shall become known in the current shell execution environment; see Section 2.12, Shell Execution Environment. If the wait utility is invoked with no operands, it shall wait until all process IDs known to the invoking shell have terminated and exit with a zero exit status.
Find elsewhere
🌐
LinuxCapable
linuxcapable.com › home › linux commands › bash wait command with examples
Bash wait Command with Examples - LinuxCapable
February 13, 2026 - The wait command is a shell built-in that pauses script execution until specified background jobs finish, then returns their exit status. Since it’s built directly into Bash (and most other shells), it executes instantly without spawning external ...
Top answer
1 of 1
30

There are two side effects of running a command asynchronously in a non-interactive shell that make A and A & wait "$!" different:

  • SIGINT and SIGQUIT are ignored for A. If you press Ctrl+C, whilst running bash -c 'sleep 1000 & wait "$!"', you'll notice bash is terminated, but not sleep.

  • A's stdin is redirected to /dev/null:

    $ bash -c 'readlink /dev/fd/0'
    /dev/pts/4
    $ bash -c 'readlink /dev/fd/0 & wait "$!"'
    /dev/null
    

Another difference is that in A | B & wait "$!" (where $! contains the pid of the process eventually running B), the exit status of A is lost ($PIPESTATUS will contain only one entry, the exit status of wait, which will be that of B if the pipefail option is not set).

In zsh, in A | B, zsh waits for both A and B, but in A | B & wait $! only waits for B (and the exit status of A is lost even with pipefail).

Another difference is that if a signal is delivered to the shell, it will be handled straight away and wait will return (even if the process it's waiting for is not finished).

Compare:

$ bash -c 'trap "echo Ouch" TERM; sleep 10 & wait "$!"; echo "$?"' & sleep 1; kill "$!"
[1] 13749
Ouch
143

Where Ouch is output as soon as SIGTERM is sent to bash (and sleep 10 carries on running after bash terminates) with:

$ bash -c 'trap "echo Ouch" TERM; sleep 10; echo "$?"' & sleep 1; kill "$!"
[1] 13822
$ Ouch                                                                                                                                        6:11
0

[1]  + done       bash -c 'trap "echo Ouch" TERM; sleep 10; echo "$?"'

Where Ouch is output only after sleep 10 returns.

Whether any of those side effects were wanted by the script author is another matter. You'll notice many other mistakes in that script, it's very well possible that whoever wrote that script didn't know much about shell scripting.

🌐
Namehero
namehero.com › blog › timing-matters-getting-to-know-the-bash-wait-command
Timing Matters: Getting To Know The Bash Wait Command
November 6, 2024 - The bash wait command is a built-in command that allows scriptwriters to pause the execution of a script until all background processes are completed. This ensures that subsequent commands are executed only after the specified processes have ...
🌐
DEV Community
dev.to › serveravatar › how-to-use-the-wait-command-in-bash-370e
How to Use the wait Command in Bash - DEV Community
August 19, 2025 - To pause the script until that background task finishes, use ‘wait’. ... #!/bin/bash echo "Starting background process..." sleep 5 & echo "Waiting for process to complete..." wait echo "Process finished."
🌐
Qmacro
qmacro.org › blog › posts › 2020 › 12 › 28 › waiting-for-jobs-and-the-concept-of-the-shell
Waiting for jobs, and the concept of the shell
December 28, 2020 - Well, it's (usually a) builtin, i.e. a command that is built in to the shell executable itself, rather than existing as a separate program. The headline description is that wait "waits for job completion and returns the exit status".
🌐
CyberPanel
cyberpanel.net › blog › bash-wait-command
Mastering Bash Wait Command: A Complete Guide
February 2, 2026 - The Bash wait command is a built-in utility that pauses script execution until specified background processes are complete. It also decides when to go ahead with the process execution.
🌐
Super User
superuser.com › questions › 1840001 › linux-bash-wait-command-not-working
ubuntu - Linux Bash Wait Command Not Working - Super User
April 22, 2024 - #!/bin/bash gnome-terminal --tab --title="1" -- bash /media/dave/Cloud/Music/2.MakeAlbums/NewMaster1.sh & wait gnome-terminal --tab --title="2" -- bash /media/dave/Cloud/Music/2.MakeAlbums/NewMaster2.sh & wait echo "Complete"
🌐
ServerAvatar |
serveravatar.com › home › blog › how to use the wait command in bash
How to Use the wait Command in Bash
September 24, 2025 - When you use ‘&’, a command runs in the background. By default, the script continues executing. To pause the script until that background task finishes, use ‘wait’. ... #!/bin/bash echo "Starting background process..." sleep 5 & echo "Waiting for process to complete..." wait echo "Process ...
🌐
Medium
copyconstruct.medium.com › bash-job-control-4a36da3e4aa7
Bash Job Control
May 29, 2019 - Builtins like kill, disown and wait operate on both processes and jobs.
🌐
Reddit
reddit.com › r/bash › how can i make wait to run properly in this case?
r/bash on Reddit: How can I make WAIT to run properly in this case?
December 29, 2022 -

I'm trying to wait for a couple of processes to finish before executing other commands, including apt update coming next in the queue, as follows:

pop-upgrade release upgrade &    # Pop!_OS tool checking for own OS updates
_PID=$(pidof pop-upgrade)
wait $_PID
apt update && apt full-upgrade -y

Here is the actual code: https://codeshare.io/Pd1xwM

This occasionally returns this output from apt:

E: Could not get lock /var/lib/apt/lists/lock. It is held by process 1485 (packagekitd) 
E: Unable to lock directory /var/lib/apt/lists/

To circumvent this, I sandwiched another wait:

pop-upgrade release upgrade &    # Pop!_OS tool checking for own OS updates
_PID=$(pidof pop-upgrade)
wait $_PID
_PID=$(pidof packagekitd)
wait $_PID
apt update && apt full-upgrade -y

But now wait throws this error message preventing the system update:

wait: pid 1485 (meaning `packagekitd`) is not a child of this shell

The thing is I'm running these commands from a script as sudo. But don't know how to deal with parents and children thingy.

How can I make wait to do its job(s) properly? Or, maybe, how can I know which process(es) prevent apt work as it should?

Thank you!

🌐
freeCodeCamp
freecodecamp.org › news › bash-sleep-how-to-make-a-shell-script-wait-n-seconds-example-command
Bash Sleep – How to Make a Shell Script Wait N Seconds (Example Command)
September 13, 2021 - Note that to achieve the same result on a MacOS or BSD machine, you would run the equivalent command sleep 150, as 2 minutes and 30 seconds is equal to 150 seconds. The sleep command is a useful way to add pauses in your Bash script.
🌐
Masteringunixshell
masteringunixshell.net › qa17 › bash-how-to-wait-seconds.html
bash how to wait seconds - Mastering UNIX Shell
'wait ${!}' waits until the last background process is completed. Was this information helpful to you? You have the power to keep it alive. Each donated € will be spent on running and expanding this page about UNIX Shell. ... We prepared for you video course Marian's BASH Video Training: ...