0

I am trying to use a named pipe to monitor the activity of a running shell script. That shell script will write to the pipe that it has "Started" processing. When it has completed processing it will write "Completed" to the pipe. A second script will perform the monitoring and will read the two messages. If the second script does not receive a "Completed" message in 5 minutes it is to send an alert.

So I found this code from the Linux Journal on using a named pipe to communicate between two processes. My immediate attempt is to get the two messages from the pipe and just display a counter as it goes through the loop, but reset back to 0 if the "Completed" message came. Adding the timing was going to be next as I wanted to make sure it was going to continuously poll the pipe for the next message. However, I am not seeing the counter increment. It appears that it waits at the read line from the pipe. Any suggestions as to what I am doing wrong?

#!/bin/bash

pipe=/tmp/testpipe

loopcnt=0 while true do echo "count: $loopcnt"

if read line <$pipe; then
    if [[ "$line" == 'Started' ]]; then
        echo $line
    elif [[ "$line" == 'Completed' ]]; then
        echo $line
        loopcnt=0
    fi
fi
((loopcnt=loopcnt+1))

done

1 Answers1

2

If the write end of the pipe is not open, then opening the read end will block until a writer appears. That will happen when the shell tries to set up the redirection, before it gets to run read itself, so timeout on read with -t doesn't by itself help.

The loop should proceed if you write anything to the pipe, though, but that won't help in finding out how much time passed, let alone in detecting if too much time passes before data is read.

The easiest way to work around that is to open the pipe in read-write mode in the reader, ensuring there always is a writer.

E.g. something like this:

#!/bin/bash

pipe=/tmp/testpipe if ! [[ -p "$pipe" ]]; then echo "'$pipe' isn't a pipe" exit 1 fi exec 3<> "$pipe" secs=0 timeout=5 while true; do if read -t 1 -u 3 line; then echo "read '$line'" secs=0 else echo . fi if ((++secs >= timeout)); then echo "no data within $timeout secs" break fi done echo end.

Though note that if $pipe doesn't exist, exec 3<> "$pipe" will create it as a regular file. Even with the explicit test to see if it is a pipe, there's a possibility the pipe is removed just between the test and the open. If that happens, the reads will immediately return with a falsy status because the file contains no data.

ilkkachu
  • 138,973
  • with a few modifications for the STARTED and COMPLETED message and this is working great. Thanks. One last question in my writer I have a write to the pipe, but then processing waits in the script until the reader reads from the pipe is there a way to make processing continue without waiting for reader? – nbmlane Aug 21 '23 at 16:49
  • @nbmlane, there's the same thing with the writer as with the reader, opening the fifo blocks until the other end is also opened. I don't think you can use FIFOs asynchronously, so that some data would be saved inside the FIFO until a future reader comes to get it. You need to arrange for the reader to have the FIFO open the whole time. – ilkkachu Aug 21 '23 at 18:24