(来源于 https://dev59.com/G2oy5IYBdhLWcg3wUcj_#8624829)
(head; tail) < file
是如何工作的?注意,cat file | (head;tail)
不起作用。
此外,为什么 (head; wc -l) < file
会给出 wc
的输出结果为 0
呢?
注意:我了解 head 和 tail 的工作原理,只是不知道这些特定调用中涉及的细节。
(来源于 https://dev59.com/G2oy5IYBdhLWcg3wUcj_#8624829)
(head; tail) < file
是如何工作的?注意,cat file | (head;tail)
不起作用。
此外,为什么 (head; wc -l) < file
会给出 wc
的输出结果为 0
呢?
注意:我了解 head 和 tail 的工作原理,只是不知道这些特定调用中涉及的细节。
如果你使用 OS X,你可以查看head 的源代码和tail 的源代码,以了解一些情况。对于 tail
,您需要查看 forward.c
。
实际上,head
并没有做什么特殊的事情。它只是使用 stdio
库读取其输入,因此它会一次读取一个缓冲区,并可能读取过多。这意味着对于小文件,cat file | (head; tail)
不起作用,因为 head
的缓冲区使其读取最后 10 行的一些(或全部)内容。
另一方面,tail
检查其输入文件的类型。如果它是一个普通文件,tail
将寻找到末尾并向后读取,直到找到足够的行数进行输出。这就是为什么 (head; tail) < file
可以在任何普通文件上工作,而不管其大小。
您也可以查看 Linux 上 head
和 tail
的源代码,但最简单的方法是使用 strace
,像这样:
(strace -o /tmp/head.trace head; strace -o /tmp/tail.trace tail) < file
看一下/tmp/head.trace
。你会发现head
命令尝试通过从标准输入(文件描述符0)读取来填充缓冲区(在我的测试中为8192字节)。根据file
的大小,它可能会或可能不会填充缓冲区。无论如何,让我们假设它在第一次读取中读取了10行。然后,它使用lseek
将文件描述符回退到第10行的末尾,实际上是“未读取”任何多余的字节。这很有效,因为文件描述符是打开在普通的可寻址文件上的。因此,(head; tail) < file
可以适用于任何可寻址文件,但它不会使cat file | (head; tail)
工作。
另一方面,tail
在我的测试中不会向OS X上那样定位到结尾并向后读取。至少它不会一直读回文件的开头。
以下是我的测试。创建一个小的12行输入文件:
yes | head -12 | cat -n > /tmp/file
然后,在Linux上尝试使用(head; tail) < /tmp/file
。 我在GNU coreutils 5.97中得到了以下结果:
1 y
2 y
3 y
4 y
5 y
6 y
7 y
8 y
9 y
10 y
11 y
12 y
但在OS X上,我得到了这个:
1 y
2 y
3 y
4 y
5 y
6 y
7 y
8 y
9 y
10 y
3 y
4 y
5 y
6 y
7 y
8 y
9 y
10 y
11 y
12 y
head
,后者会回显前10行并关闭管道,然后子shell将其stdin连接到tail
,后者会消耗剩余的内容并将最后10行写回stdout,但子shell会接收两个输出,并将它们作为自己的stdout写入,这就是为什么看起来是混合的。{ head; tail; } < file
,这更便宜,因为它不会创建另一个bash实例。for i in `seq 1 10`; do echo "foo"; done | (head -n1; wc -l)
每次使用wc命令时,文件的数量应该不同。
当使用<
输入时,似乎不存在这种并行性(可能是因为bash读取整个输入然后将其传递给head命令)。
head命令显示文件的前10行(默认值)。tail命令显示文件的最后10行(默认值)。 假设文件只有3行,这些命令也可以显示这些行。 但是如果您有超过10行,则这两个命令将仅显示默认的10行。 可以使用-n、n、+n选项更改默认行数。(请参阅man页面)
cat file | (head;tail)
不行?这个命令在我这里可以正常使用。另外,你为什么说(head; wc -l) < file
输出结果为0呢?这个命令在我这里也可以正常使用。你使用的是什么系统和Bash版本?是否有特定的文件无法使用?这些文件的行数是少于10行、10-20行还是多于20行呢? - Brian Campbellwc -l
给出的是文件中的行数-10
,我猜这是预期的?我不知道这个语法,非常酷。 - Linus Thiel$ curl -s http://www.wikipedia.org/ | ( head -n 2; echo "#--#"; tail -n 1; )
运行良好,但$ yes | head -12 | cat -n | ( head -n 2; echo "#--#"; tail -n 1; )
只显示头部输出。这可能是答案中提到的头部缓冲区问题,因为$ yes | head -5000 | cat -n | ( head -n 2; echo "#--#"; tail -n 1; )
运行得很好。 - Stephen