bash zcat头导致pipefail?

cmo*_*cmo 9 bash

set -eu 
VAR=$(zcat file.gz  |  head -n 12)
Run Code Online (Sandbox Code Playgroud)

工作良好

set -eu   -o pipefail
VAR=$(zcat file.gz  |  head -n 12)
Run Code Online (Sandbox Code Playgroud)

导致bash退出失败.这怎么会导致管道故障?

请注意,file.gz包含数百万行(约750 MB,已压缩).

Cha*_*ffy 19

想一想,片刻.

  1. 您告诉shell,如果任何组件发生故障,应该认为整个管道都已失败.
  2. 你要告诉你zcat输出它的输出head.
  3. 然后你会head在读取12行之后退出,超过12行的输入流.

当然你有一个错误:zcat有目的地管道早关闭,是不是能够成功地编写输入文件的解压缩版本!它没有任何方式知道这是由于用户意图,通过错误发生的事情.

如果您正在使用zcat写入磁盘并且空间不足或网络流耗尽而且连接丢失,那么退出并指示失败的状态将是完全正确的.这只是该规则的另一种情况.


由syscall在以下条件下返回zcat操作系统给出的特定错误:尝试写入未打开以供任何进程读取的管道.EPIPEwrite

head(此FIFO的唯一读取器)退出之后,对于管道输入端的任何写入都不会返回EPIPE将是一个错误.为了zcat静默地忽略写入其输出的错误,从而能够生成不准确的输出流而没有反映此事件的退出状态,同样也是一个错误.


如果您不想更改任何shell选项,顺便提一下,您可能会考虑使用进程替换的一种解决方法:

var=$(head -n 12 < <(zcat file.gz))
Run Code Online (Sandbox Code Playgroud)

在这种情况下,zcat不是管道组件,并且不考虑其退出状态以确定成功.($var如果您想要进行独立的成功/失败判断,您可以测试是否长12行.

  • 出色的答案!谢谢你的细节。尽管这些事情对于受过训练的计算机程序员或经验丰富的编码人员而言可能是显而易见的,但仍有许多人编写的脚本和代码不是经过培训的计算机科学家,而且我们中的许多人都是自学成才的。现实情况是,我们中许多业余爱好者没有时间甚至没有知识来研究bash,管道,流,系统调用等的内部工作原理。当您不了解流的详细信息时, “写”等,通过纯粹的想象可以想象)“头”正确终止了文件流。 (2认同)