How can I implement a timeout when no data is being passed through a pipe? It would act as watchdog with following usage:

process1 | watchdog --timeout 60 | process2

When no data pipes through I would like the watchdog process to close.



To begin with the watchdog pipeline from your question would probably not kill the process1 unless it is trying again to write to the dead pipe. So your watchdog should somehow explicitly kill process1.

Beside this here a very simple watchdog.sh shell script. You can test it interactively in console. Just type ./watchdog.sh. It will duplicate everything you type then and stop if you don't type something for 5 seconds.


# first arg is timeout (default: 5)

exec tee >(bash -c '
while true ; do
    bytes=$(timeout '$T' cat | wc -c)
    if ! [ "$bytes" -gt 0 ] ;then
## add something like "killall process1", for now we just kill this tee command
kill -9 '$PID)

Note the script will actually timeout between T and 2*T (otherwise it would be way more complicated). Somehow you could add a way to kill process1 as I initially mentioned.

Below an example for testing.



echo "here we are ..."
sleep 2
echo "still alive ..."
sleep 20
echo "too late ..."

And run it like this (inclusive an ugly method to kill process1.sh on timeout):

(./process1.sh & echo $! >/tmp/pid; wait) |(./watchdog.sh 5; kill `cat /tmp/pid`)
  • Thanks, that looks very promising. I do have binary data, would that work alright? If I understand correctly, it's based on cat. – Tynix Nov 18 '16 at 15:56
  • tee is copying the data through the pipe without changing it. I've added an example for testing. – rudimeier Nov 18 '16 at 17:00

This might not be ideal in terms of performance, and it's line based, but the timeout feature of the read command might be used for this. In bash, you can then use a command line stanza like the following as your watchdog --timeout 60 part:

while read -r -s -t 60 line ; do printf "%s\n" "$line" ; done

zsh offers a similar read command.

Note however, that it won't actually terminate the overall command until the first part, i.e., your process1, decides to terminate due to its standard output being closed.


An alternative view of the problem might be to remove the watchdog out of the pipe, and stat the pipe for its last modification time. For example,

process1 &
while   new=$(stat -L /dev/stderr -c %Y)
        [ $new != $old ]
do      old=$new
        sleep 60
done 3>&2 2>&1 1>&3   &&   kill -hup $pid
) |

This puts process1 into the background so we can get its pid, then polls the last modification time of the output pipe. If it doesn't change in 60 seconds, we can kill the pid. To be able to capture the output of stat we swap file descriptor 1, which is the pipe, with stderr and stat that instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.