In a shell script, how can I (1) start a command in the background (2) wait x seconds (3) run a second command while that command is running?
Solution 1
Unless I'm misunderstanding your question, it can simply be achieved with this short script:
#!/bin/bash
process_a &
sleep x
process_b
(and add an extra wait
at the end if you want your script to wait for process_a
to finish before exiting).
You can even do this as an one-liner, without the need for a script (as suggested by @BaardKopperud):
process_a & sleep x ; process_b
Solution 2
You can use the background control operator (&) to run a process in the background and the sleep
command to wait before running a second process, i.e.:
#!/usr/bin/env bash
# script.sh
command1 &
sleep x
command2
Here is an example of two commands that print out some time-stamped messages:
#!/usr/bin/env bash
# Execute a process in the background
echo "$(date) - Running first process in the background..."
for i in {1..1000}; do
echo "$(date) - I am running in the background";
sleep 1;
done &> background-process-output.txt &
# Wait for 5 seconds
echo "$(date) - Sleeping..."
sleep 5
# Execute a second process in the foreground
echo "$(date) - Running second process in the foreground..."
for i in {1..1000}; do
echo "$(date) - I am running in the foreground";
sleep 1;
done
Run it to verify that it exhibits the desired behavior:
user@host:~$ bash script.sh
Fri Dec 1 13:41:10 CST 2017 - Running first process in the background...
Fri Dec 1 13:41:10 CST 2017 - Sleeping...
Fri Dec 1 13:41:15 CST 2017 - Running second process in the foreground...
Fri Dec 1 13:41:15 CST 2017 - I am running in the foreground
Fri Dec 1 13:41:16 CST 2017 - I am running in the foreground
Fri Dec 1 13:41:17 CST 2017 - I am running in the foreground
Fri Dec 1 13:41:18 CST 2017 - I am running in the foreground
Fri Dec 1 13:41:19 CST 2017 - I am running in the foreground
Fri Dec 1 13:41:20 CST 2017 - I am running in the foreground
...
...
...
Solution 3
I like @dr01's answer but he doesn't check the exit code and so you don't know if you were successful or not.
Here's a solution that checks the exitcodes.
#!/bin/bash
# run processes
process_a &
PID1=$!
sleep x
process_b &
PID2=$!
exitcode=0
# check the exitcode for process A
wait $PID1
if (($? != 0)); then
echo "ERROR: process_a exited with non-zero exitcode" >&2
exitcode=$((exitcode+1))
fi
# check the exitcode for process B
wait $PID2
if (($? != 0)); then
echo "ERROR: process_b exited with non-zero exitcode" >&2
exitcode=$((exitcode+1))
fi
exit ${exitcode}
usually i store the PIDs in a bash array and then the pid checking is a for loop.
Related videos on Youtube
Julie
Updated on September 18, 2022Comments
-
Julie almost 2 years
This is what I need to happen:
- start process A in the background
- wait for x seconds
- start process B in the foreground
How can I make the wait happen?
I'm seeing that 'sleep' seems to halt everything and I don't actually want to 'wait' for process A to finish entirely. I've seen some time based loops but I'm wondering if there's something cleaner.
-
Charles Duffy over 6 yearsWhere do you get the impression that
sleep
halts process-A? Can you show the test process you're using, or output indicative of this? If process-A is halting, it's more likely that it's trying to read from the terminal while running in the background and getting halted for that reason, rather than anything related tosleep
. -
Charles Duffy over 6 years...if that is the case,
process_a </dev/null &
will attach its stdin to/dev/null
rather than the TTY, and that may be sufficient to avoid the problem. -
MADforFUNandHappy over 6 yearsFrom my experience sleep will only block the current process and thus not the process previously started in the background with &
-
Stéphane Chazelas over 6 yearsNote that you don't need
bash
for that, any shell will do including your system'ssh
, so you don't need to add a dependency on bash for your script. -
Stéphane Chazelas over 6 yearsYou may want to reflect those exit codes in the exit status of your script like
A & sleep x; B; ret=$?; wait "$!" || exit "$ret"
-
Trevor Boyd Smith over 6 years@StéphaneChazelas good idea. i updated the code to make sure a non-zero exitcode is returned if one or both fail.
-
Sparhawk over 6 yearsThe question asks to "start process B in the foreground".
-
igal over 6 years@Sparhawk Wow. Totally misread that - no explanation. Thanks for the heads-up - code corrected. Serious nostalgia from your username, btw.
-
Sparhawk over 6 yearsNo worries! (Also the username was originally a reference to this chap, but I only later realised it was an Eddings character! And makes me want to re-read those books…)
-
Peter Cordes over 6 yearsThe OP wants
process_b
running in the foreground. Presumablyprocess_a
could exit whileprocess_b
is running, but you can stillwait
for it and get the exit status after you've collected the exit status of the foregroundprocess_b
the normal way, with$?
directly. -
Baard Kopperud over 6 yearsOr simply: process_a & sleep x ; process_b