"(head; tail)<file"如何工作?

zel*_*lyn 28 bash shell

(通过/sf/answers/603738061/)

(head; tail) < file工作怎么样?请注意,cat file | (head;tail)没有.

此外,为什么(head; wc -l) < file0了输出wc

注意:我理解头尾的工作原理.只是不是这些特定调用涉及的微妙之处.

rob*_*off 19

OS X.

对于OS X,您可以查看源代码head源代码,tail以找出正在发生的一些事情.在这种情况下tail,你会想看看forward.c.

所以,事实证明这head并没有做任何特别的事情.它只是使用stdio库读取它的输入,因此它一次读取一个缓冲区并且可能读取太多.这意味着cat file | (head; tail)不适用于小文件,其中head缓冲使其读取最后10行中的一些(或全部).

另一方面,tail检查其输入文件的类型.如果它是一个常规文件,tail则搜索结束并向后读取,直到找到足够的行发出.这就是(head; tail) < file适用于任何常规文件的原因,无论大小如何.

Linux的

你可以看看源headtailLinux上也一样,但它更容易,只需使用strace,就像这样:

(strace -o /tmp/head.trace head; strace -o /tmp/tail.trace tail) < file
Run Code Online (Sandbox Code Playgroud)

看看/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
Run Code Online (Sandbox Code Playgroud)

然后,试试(head; tail) < /tmp/fileLinux.我用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
Run Code Online (Sandbox Code Playgroud)

但是在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
Run Code Online (Sandbox Code Playgroud)


Sam*_*us_ 7

这里的括号创建一个subshell解释器的另一个实例来运行里面的命令,有趣的是子shell充当单个stdin/stdout组合; 在这种情况下,它将首先连接stdin head,回显前10行并关闭管道,然后subshel​​l连接其stdin tail消耗其余的stdin 并将最后10行写回到stdout,但子shell接受两个输出并写入它们作为自己的标准输出,这就是它出现组合的原因.

值得一提的是,同样的效果可以用实现命令分组一样{ head; tail; } < file是便宜,因为它不会产生庆典的另一个实例.