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
2

1 Answer 1

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.

2
  • 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
    Commented Aug 21, 2023 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
    Commented Aug 21, 2023 at 18:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .