为什么用grep -q退出代码141?

San*_*ing 35 linux bash freebsd

有人可以解释为什么我从下面得到退出代码141?

#!/usr/bin/bash

set -o pipefail

zfs list | grep tank
echo a ${PIPESTATUS[@]}

zfs list | grep -q tank
echo b ${PIPESTATUS[@]}

cat /etc/passwd | grep -q root
echo c ${PIPESTATUS[@]}
Run Code Online (Sandbox Code Playgroud)

我明白了

...
a 0 0
b 141 0
c 0 0
Run Code Online (Sandbox Code Playgroud)

从我的理解退出代码141失败,但上面的行给出零,所以它应该是成功,我会说.

dog*_*ane 53

这是因为grep -q一找到匹配就立即退出零状态.该zfs命令仍在写入管道,但没有读取器(因为grep已退出),因此它SIGPIPE从内核发送信号并以状态为退出141.

另一个你看到这种行为的常见地方是head.例如

$ seq 1 10000 | head -1
1

$ echo ${PIPESTATUS[@]}
141 0
Run Code Online (Sandbox Code Playgroud)

在这种情况下,head读取第一行并终止生成SIGPIPE信号并seq退出141.

请参阅Linux程序员指南中的" 臭名昭着的SIGPIPE信号 ".

  • 传统上,退出状态*N*大于128表示程序被信号*N* - 128终止.由于`SIGPIPE`是信号13,141-128 = 13表示你的程序是由`SIGPIPE`结束的. (25认同)
  • 有没有一种方法我仍然可以使用`set -o pipefail`和`grep -q`,因为我想保留它,因为我有很多来自SSH的解析. (12认同)
  • @chepner:这不是常规问题,而是shell如何处理由于信号而退出的进程.对于bash,它是128 + signal_number,但其他shell使用其他公式.看到这篇优秀的帖子:http://unix.stackexchange.com/a/99134/9041 (3认同)
  • @SandraSchlichting:请参阅[有效SIGPIPE处理](http://www.pixelbeat.org/programming/sigpipe_handling.html),了解bash中的pipefail及其替代方法的问题。 (3认同)
  • @SandraSchlichting:我有同样的问题,这很烦人。一个想法:不要将 `-q` 选项与 `grep` 一起使用,而是重定向输出:`1> /dev/null 2>&1`。理论上,`grep` 处理整个输入会稍微慢一点,但实际上:它可以工作。 (2认同)
  • 这里提供了一个有趣但详细的“SIGPIPE”和“pipefail”解决方案:https://unix.stackexchange.com/a/582850/66344 (2认同)

小智 5

我不熟悉zfs list,但是我猜它抱怨它的标准输出被关闭了- grep -q找到匹配项后立即退出,这与grep