名前付きパイプが読み取り用に開いているかどうかを確認します

名前付きパイプが読み取り用に開いているかどうかを確認します

現在、名前付きパイプが読み取られているかどうかを確認するために、次のようなひどいチェックを行っています。

is_named_pipe_being_read() {

    local named_pipe="$1" 
    echo "unlocked" > "$named_pipe" & 
    pid="$!"
    # Wait a short amount of time
    sleep 0.25
    # Kill the background process. If kill succeeds, then
    # the write was blocked 
    ( kill -PIPE "$pid" ) &> /dev/null
}

キルが機能する場合 (0 で終了する場合)、パイプから読み取る人がいなかったことを意味します。

しかし、0.25 秒の遅延が発生して不要なプロセスが起動されるのではなく、名前付きパイプが読み取り用に開かれているかどうかを確認する方法を探しています。何かがそこから読み取られているかどうかを判断する方法はありますか?

注記: この呼び出しではパイプから読み取ることはできず、パイプに書き込むことしかできません (名前付きパイプでは、リーダーが接続される順序が尊重されないようです。または、データを取得するのは最も古いリーダーではなく、最新のリーダーである可能性があります)。

答え1

if /bin/echo unlocked 1<>fifo >fifo; then
    there are readers
else
    no there ain\'t
fi

is_named_pipe_being_read(){ /bin/echo unlocked 1<>"$1" >"$1"; }

/bin/echoによって強制終了されSIGPIPE、リーダーが存在しない場合はゼロ以外のステータスを返します。

がキャッチされるかシェル全体が強制終了されるため、組み込みの は使用できませんecho(サブシェル内であっても) 。SIGPIPE

OP のバージョンと同様に、これは破壊的です。GNU dd をお持ちの場合は、次O_NONBLOCKのようにしてファイルを開いてみてくださいC

is_named_pipe_being_read(){ dd oflag=nonblock conv=notrunc,nocreat count=0 of="$1" 2>/dev/null; }

しかし、これはあまり良くありません。パイプに他の書き込みがある場合、コマンド終了時に FIFO が自動的に閉じられるため、すべてのリーダーが EOF を取得します。

注記:名前付きパイプの使用は、むしろマゾヒズムまたは標準的な衒学的態度の問題です [1]。Unix ドメイン ソケットによって実装された BSD ソケット API は比較にならないほど優れています (それが世界を制覇する理由です ;-))。また、新しいバージョンのようなプログラムでは、netcatシェルからもある程度使用できます。

[1] 上記のような例では無効です。これ標準によれば、FIFO を rw モードで開くことは「未定義」ですが、30 年ほど前からほとんどのシステムで同じように実装されています。

答え2

このCプログラムはhttps://stackoverflow.com/a/20694422/5047085:

#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#include <sys/stat.h>

#define SERVFIFO "/Users/alex/.locking/ql/locks/a/fifo.lock"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

void syserr(const char *str){
    perror(str);
    exit(1);
}

int main(int argc, char** argv){

    umask(0);

    // try to open for write with no readers

    int fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);

    if (fdw == -1){
      syserr("non-blocking open for write with no readers failed");
    }

    // create a reader - the process itself - non-blocking

    int fdr = open(SERVFIFO, O_RDONLY | O_NONBLOCK);
    if (fdr == -1){
      syserr("non-blocking open for read no writers failed");
    }

    // try again to open for write but this time with a reader
    fdw = open(SERVFIFO, O_WRONLY | O_NONBLOCK);

    if (fdw == -1){
      syserr("non-blocking open with readers failed");
    }


    printf("non-blocking open for write succeeded\n");

    close(fdw);
    close(fdr);

}

0 で終了した場合、すでに誰かが名前付きパイプから読み取っていることを意味しますか? 1 で終了した場合、誰も読み取っていないことを意味します。

これは間違っている可能性がありますが、基本的なテストでは動作することが示されています。 fifo パスは上記のプログラムでハードコードされています。

関連情報