bash "wc -l"如果调用或通过 tee 命令输出不同

标签 bash tee wc process-substitution

当我在 Bash 中发出两个等效命令时,我得到了不同的输出(来自“wc -l”命令),见下文:

root@devel:~# ls /usr/bin -lha | tee >(wc -l) >(head) > /dev/null
total 76M
drwxr-xr-x  2 root root      20K Nov 11 18:58 .
drwxr-xr-x 10 root root     4.0K Oct  8 15:31 ..
-rwxr-xr-x  1 root root      51K Feb 22  2017 [
-rwxr-xr-x  1 root root       96 Jan 19  2017 2to3-3.5
-rwxr-xr-x  1 root root      23K Mar 22  2017 addpart
lrwxrwxrwx  1 root root       26 May 10  2017 addr2line -> x86_64-linux-gnu-    addr2line
lrwxrwxrwx  1 root root        6 Dec 13  2016 apropos -> whatis
-rwxr-xr-x  1 root root      15K Sep 13 19:47 apt
-rwxr-xr-x  1 root root      79K Sep 13 19:47 apt-cache
137
root@devel:~# ls /usr/bin -lha | wc -l
648

我错过了什么?

这很奇怪,但是当我这样调用它时,它会得到更奇怪的输出:

root@devel:~# ls /usr/bin -lha | tee >(wc) >(wc) > /dev/null
648    6121   39179
648    6121   39179
root@devel:~# ls /usr/bin -lha | tee >(wc) >(wc) > /dev/null
648    6121   39179
648    6121   39179
root@devel:~# ls /usr/bin -lha | tee >(wc) >(wc -l) > /dev/null
648
root@devel:~#     648    6121   39179

似乎命令异步运行并在不同时间结束......或者它可能是什么?

最佳答案

简单回答:

如何修复:

ls /usr/bin -lha | tee <b>--output-error=exit-nopipe</b> >(wc -l) >(head) > /dev/null

详情:

命令 head 只打印输入的头部,所以只要它获得足够的输入就可以完成它的工作,然后退出而不等待所有输入。

所以让我们用简单的“head”替换命令head

ls /usr/bin -lha | tee >(wc -l) <b>>(read l; echo $l)</b> > /dev/null

简单的 “head” 将只读取一行,然后退出,这导致管道文件在 tee 完成向其传输所有数据之前立即关闭。

毫无疑问,使用简单的 “head” 会得到相同的结果。 wc 仍然打印错误的数字。

您的问题的根本原因,我想您可以自己总结,是 tee 的输出管道之一较早关闭,tee 命中 写入错误,然后停止写入其他输出文件。

了解了根本原因后,我想您将很容易理解手册页中的以下部分。

MODE determines behavior with write errors on the outputs:
   'warn' diagnose errors writing to any output

   'warn-nopipe'
          diagnose errors writing to any output not a pipe

   'exit' exit on error writing to any output

   'exit-nopipe'
          exit on error writing to any output not a pipe

   The  default MODE for the -p option is 'warn-nopipe'.  The default operation
   when --output-error is not specified, is to exit immediately on error writing to
   a pipe, and diagnose errors writing to non pipe outputs.

一些多余的话

实际上,如果您在有问题的命令行中将 >(wc -l) 替换为常规文件,您会发现文件大小始终为 16384 或 20480 或 32768 或 36864 或 28672 或 . ..,都是4096的倍数。(写入常规文件未完成,因为tee提前中止。如果写入完成,文件大小将是任意值。)

4096 是大多数类 UNIX 系统的 PIPE_BUF 的值。如果你知道 PIPE_BUF 是什么,你就会很容易理解为什么文件大小总是 4096 的倍数。

关于bash "wc -l"如果调用或通过 tee 命令输出不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47253210/

相关文章:

python - 尽管 Shell 脚本已在 Mac OS X 登录项中注册,但它不会自动运行

linux - 在 Imagemagick 中使用循环裁剪图像

linux - 不使用 tee 命令打印到 shell 的正确方法

shell - 计算一个句子中的字符、单词、单词长度和总长度

linux - wc -l 的性能

bash - 在 Unix 中使用 bash 查找指定大小的文件

linux - bash 脚本 : if use with (conditon) or [condition]

bash:将 stdout 和 stderr 重定向(并附加)到文件和终端并获得正确的退出状态

bash - 在 bash 脚本中间切换输出文件重定向

linux - 列出所有文件并将文件计数作为 $BASH 中的输出列之一?