检查命名管道是否打开以供读取

Ale*_*lls 2 shell bash fifo

现在,我有一个蹩脚的检查来查看是否正在读取命名管道:

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
}
Run Code Online (Sandbox Code Playgroud)

如果终止有效(以 0 退出),则意味着没有人从管道中读取数据。

但我不想有 0.25 秒的延迟并启动不必要的进程,而是寻找一种方法来检查命名管道以查看它是否已打开以供读取?有没有办法确定是否有东西正在从中读取?

注意:我无法在这次调用中从管道中读取数据,我只能写入它(因为使用命名管道,读取器的附加顺序似乎不受尊重 - 或者可能是最近获取数据的读取器,不是最老的读者)。

小智 5

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"; }
Run Code Online (Sandbox Code Playgroud)

如果没有读者,则会/bin/echo被 a 杀死SIGPIPE并返回非零状态。

您不能使用内置函数echo(即使在子 shell 中),因为它将SIGPIPE被捕获或杀死整个 shell。

就像OP的版本一样,这是破坏性的。如果您有 GNU dd,您可以尝试使用 打开文件O_NONBLOCK,如下所示C

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

但这也好不了多少;如果管道中有其他写入者,则在命令退出时自动关闭 fifo 将导致所有读取者获得 EOF。

注意:使用命名管道更多的是一种受虐狂或标准的迂腐行为 [1]。由 unix 域套接字实现的 BSD 套接字 API 是无与伦比的好(这就是它统治世界的原因;-)),并且有一些程序(例如较新版本的程序)netcat使其也可以从 shell 中使用。

[1] 在上面或这个例子中,根据标准,在 rw 模式下打开 fifo 是“未定义”的,尽管从 30 年前左右开始在大多数系统中实现了相同的实现,但这一点被击败了))。