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"