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?

6,825

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.

Share:
6,825

Related videos on Youtube

Julie
Author by

Julie

Updated on September 18, 2022

Comments

  • Julie
    Julie almost 2 years

    This is what I need to happen:

    1. start process A in the background
    2. wait for x seconds
    3. 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
      Charles Duffy over 6 years
      Where 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 to sleep.
    • Charles Duffy
      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
      MADforFUNandHappy over 6 years
      From my experience sleep will only block the current process and thus not the process previously started in the background with &
  • Stéphane Chazelas
    Stéphane Chazelas over 6 years
    Note that you don't need bash for that, any shell will do including your system's sh, so you don't need to add a dependency on bash for your script.
  • Stéphane Chazelas
    Stéphane Chazelas over 6 years
    You 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
    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
    Sparhawk over 6 years
    The question asks to "start process B in the foreground".
  • igal
    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
    Sparhawk over 6 years
    No 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
    Peter Cordes over 6 years
    The OP wants process_b running in the foreground. Presumably process_a could exit while process_b is running, but you can still wait for it and get the exit status after you've collected the exit status of the foreground process_b the normal way, with $? directly.
  • Baard Kopperud
    Baard Kopperud over 6 years
    Or simply: process_a & sleep x ; process_b