写入 FIFO 时捕获 SIGPIPE

写入 FIFO 时捕获 SIGPIPE

这些是重现问题的步骤。

writer:

#!/bin/bash
trap 'echo NoReader!' PIPE
cat > fifo

打开两个终端。我将用下面的>T1<>T2<标题来表示它们,并用 来表示它们的提示$

>T1<
$ mkfifo fifo
$ bash writer
ABC
>T2<
$ cat fifo
ABC
^C
>T1<
DEF
$ echo $?
141

man fifo,

当进程尝试写入另一端未打开以供读取的 FIFO 时,会向该进程发送 SIGPIPE 信号。

当我进入时DEF,FIFO 已经没有读取器了。所以我预计 SIGPIPE 上的陷阱在输入后会被触发DEF并显示相应的NoReader! 消息。相反,该进程会默默终止。错误代码是141,这表明它确实被 SIGPIPE 终止了

另一方面,执行这个newWriter

#!/bin/bash
trap 'echo NoReader!' PIPE
var=$(head -c 100000 /dev/urandom)
echo "$var" > fifo

在终端 1 和head -c 1 fifo终端 2 确实触发了陷阱!但是,如果我只是从 urandom 中提取 1000 个字节而不是 100000 个字节,则不会触发陷阱。

我缺少什么?为什么第一个示例中没有触发陷阱writer,而是在newWriter100000 字节(而不是 1000 字节)中触发?

答案1

陷阱处理程序未执行的原因bash很简单,就是bash没有收到该信号。它仅被发送到写入进程,即cat

如果是 shell 本身执行写入操作,则会执行陷阱处理程序:

#!/bin/bash

exec 3>fifo
trap 'echo NoReader!' PIPE
while IFS= read -r -d '' -n 1 input; do
    printf %s "$input" >&3 || break
done </dev/urandom

strace显示了调用不同行为的原因head: FIFO 缓冲 4096 字节(在我的系统上;不知何故可以从内核检索该值)。因此,使用-c 4096but 时不应出现错误4097

相关内容