Bash – timeout without killing process in bash

bashkilllinuxtimeout

I have a main script that I'm running, and from it I have a second "slow process" I want to kick off, and "do something" in the main script if it doesn't complete in the time limit — depending on if it completed or not. N.B. If the "slow process" finishes before my time limit, I don't want to have to wait an entire time limit.

I want the "slow process" to keep going so I can gather stats and forensics about it's performance.

I've looked into using timeout, however it will kill my script when finished.

Suppose this simplified example.

main.sh

result=`timeout 3 ./slowprocess.sh`
if [ "$result" = "Complete" ]
then
 echo "Cool it completed, do stuff..."
else
 echo "It didn't complete, do something else..."
fi

slowprocess.sh

#!/bin/bash
start=`date +%s`
sleep 5
end=`date +%s`
total=`expr $end - $start`
echo $total >> /tmp/performance.log
echo "Complete"

Here, it uses timeout — so the script dies, so nothing winds up in /tmp/performance.log — I want slowprocess.sh to complete, but, I want main.sh to go onto its next step even if it doesn't finish in the 3 seconds.

Best Answer

With ksh/bash/zsh:

{
  (./slowprocess.sh >&3 3>&-; echo "$?") |
    if read -t 3 status; then
      echo "Cool it completed with status $status, do stuff..."
    else
      echo "It didn't complete, do something else..."
    fi
} 3>&1

We duplicate the original stdout onto fd 3 (3>&1) so we can restore it for slowprocess.sh (>&3), while stdout for the rest of the (...) subshell goes to the pipe to read -t 3.

Alternatively, if you want to use timeout (here assuming GNU timeout):

timeout --foreground 3 sh -c './slowprocess.sh;exit'

would avoid slowprocess.sh being killed (the ;exit is necessary for sh implementations that optimise by executing the last command in the shell process).

Related Question