timeout without killing process in bash

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).


Here's a solution using only ubiquitous shell tools.

This should be easily done by forking the slow process and a sleep in the background and waiting for the first to finish, except that the wait shell builtin waits for all jobs to finish rather than only for the first one.

So instead, fork the slow process and a sleep in the background, have them both report their status through a pipe, and read the first status that comes out of the pipe.

fifo=$(mktemp -u)  # if not on Linux, adapt to what your OS provides
mkfifo -m 600 "$fifo"
{ ./slowprocess.sh; echo z >"$fifo"; } &
sh -c 'sleep 3; echo a' >"$fifo" &
sleep_pgid=$!
read status <$fifo
case $status in
  a) echo "That process is taking a long time"; read ignored <$fifo;;
  z) echo "Done already"; kill -INT -$sleep_pgid;;
esac
rm "$fifo"