有人可以解释为什么我从下面得到退出代码 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[@]}
我明白了
...
a 0 0
b 141 0
c 0 0
根据我的理解,退出代码 141 是失败,但上面的行给出零,所以我想说它应该是成功。
这是因为一旦找到匹配项,
grep -q
就会立即以零状态退出。 zfs
命令仍在写入管道,但没有读取器(因为 grep
已退出),因此从内核向它发送了 SIGPIPE
信号,并以 141
状态退出。
您看到此行为的另一个常见地方是使用
head
。例如
$ seq 1 10000 | head -1
1
$ echo ${PIPESTATUS[@]}
141 0
在这种情况下,
head
读取第一行并终止,生成SIGPIPE
信号,并且seq
以141
退出。
请参阅《Linux 程序员指南》中的“臭名昭著的 SIGPIPE 信号”。
我不熟悉
zfs list
,但我猜它抱怨其标准输出被关闭 - grep -q
在找到匹配项时立即退出,与 grep
不同。
另一种选择是不使用管道,而是使用进程替换:
grep -q 坦克 <(zfs list)
更新:我想是一样的,因为括号内运行的进程也会收到 sigpipe。
你可以继续吃输出,例如:
command | { grep -q whatever; cat >/dev/null; }