bash命令"wc -l"通过直接调用和通过tee调用输出不同的结果。

8

当我在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

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

1
是的,进程替换是异步运行的,请参阅手册 - Benjamin W.
1
好的,但是如何修复它?如何让程序等待真正的输出结束?还是这里没有解决方案? - urusai_na
你想要实现什么目标?是同时获取 ls | headls | wc -l 的输出吗? - Benjamin W.
是的,但“wc -l”只得到了137行,而不是648行,为什么?这似乎与异步无关,因为在第二个变体中,我总是得到648行。 - urusai_na
是的@dave_thompson_085,你的发现是正确的。楼主,你想做什么?一定有另一种方法可以实现你想要的,而不会遇到那种情况。 - Nic3500
显示剩余2条评论
1个回答

8

简单回答:

如何修复:

ls /usr/bin -lha | tee --output-error=exit-nopipe >(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的倍数。


命令说明:此处有解释。 - Sebastian Breit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接