Check whether named pipe/FIFO is open for writing

Update 2: After playing with inotify-tools, there doesn't seem to be a way to get a notification that a named pipe has been opened for writing and is blocking. This is probably why lsof doesn't show the pipe until it has a reader and a writer.

Update: After researching named pipes, I don't believe that there is any method that will work with named pipes by themselves. Reasoning:

  • there is no way to limit the number of writers to a named pipe (without resorting to locking)
  • all writers block if there is no reader
  • no writers block if there is a reader (presumably as long as the kernel buffers aren't full)

You could try writing nothing to the pipe with a short timeout. If the timeout expires, then the write blocked indicating that someone has already opened the pipe for writing.

Note: As pointed out in the comments, if a reader exists and presumably is fast enough, our test write will not block and the test essentially fails. Comment out the cat line below to test this.

#!/bin/bash

is_named_pipe_already_opened_for_writing() {
    local named_pipe="$1"
    # Make sure it's a named pipe
    if ! [ -p "$named_pipe" ]; then
        return 1
    fi
    # Try to write zero bytes in the background
    echo -n > "$named_pipe" &
    pid=$!
    # Wait a short amount of time
    sleep 0.1
    # Kill the background process. If kill succeeds, then
    # the write was blocked indicating that someone
    # else is already writing to the named pipe.
    kill $pid 2>/dev/null
}

PIPE=/tmp/foo

# Ignore any bash messages from killing below
trap : TERM

mkfifo $PIPE
# a writer
yes > $PIPE &
# a reader
cat $PIPE >/dev/null &

if is_named_pipe_already_opened_for_writing "$PIPE"; then
    echo "$PIPE is already being written to by another process"
else
    echo "$PIPE is NOT being written to by another process"
fi

jobs -pr | kill 2>/dev/null
rm -f $PIPE