SIGPIPE 和 bash 管道失败

SIGPIPE 和 bash 管道失败

我试图更好地理解 Linux 上的 SIGPIPE。

我运行了这个实验:{ ls -al /tmp/ ; echo "$?" 1>&2 ; } | head 它回显了141我所理解的退出代码,该退出代码是给予退出的进程SIGPIPE 之前,我已经做了很多次,但没有理解 的细微差别SIGPIPE,而且我通常运行set -eEuo pipefail所以,我试图理解为什么我的由于管道损坏,代码并不是一直失败...所以我运行了另一个实验:( set -o pipefail; { ls -al /tmp/ ; echo "$?" 1>&2 ; } | head; )那一次我在回显中得到了 0...所以当pipefail启用时,这是否意味着它SIGPIPE被抑制了?或者我误解了这里发生的事情?

答案1

ls即使 的输出比打印的内容长,也可以在head退出并破坏管道之前设法写入所有输出。这是因为:lshead

  • head阅读的内容可能比最终打印的内容多,
  • 无论如何,管道都有一个缓冲区。

SIGPIPE 是通过实际写入损坏的管道来触发的。如果在退出ls之前设法写入所有输出head,则不会有任何写入行为触发 SIGPIPE。

或者ls可能无法在head退出之前写入所有输出。然后它会尝试写入更多内容并收到 SIGPIPE。

由于lshead并行运行,我认为一般来说存在竞争条件。可能会发生某些特定输出ls随机触发或不触发 SIGPIPE 的情况。

尝试使用yes而不是ls …

{ yes ; echo "$?" 1>&2 ; } | head

或者

( set -o pipefail; { yes ; echo "$?" 1>&2 ; } | head; )

yes生成的输出不会自行结束,因此head退出后总会有一个触发 SIGPIPE 的写入行为。上面的每个命令都会给你141肯定的信息。

这与 无关pipefail

相关内容