头部是否会消耗stdin中的其他字符?

时间:2014-03-03 13:09:56

标签: linux bash shell

当我执行以下head命令时:

yes 123456789 | ( head -n 1; head -n 1 )

我明白了:

123456789
3456789

虽然我期待:

123456789
123456789

当我执行时,我也很困惑:

echo -e "123456789\n123456789\n123456789\n123456789\n123456789\n" | \
( head -n 1; head -n 1 )

我明白了:

123456789

而不是:

123456789
123456789

我想有些事我不明白。你知道我为什么会这样做吗?

4 个答案:

答案 0 :(得分:7)

输入和输出是完全不同的野兽。 head的手册告诉您预期的输出是什么,但它没有告诉您有关如何处理输入的任何信息。

所以简短的回答是:你依赖于无证件的东西。

现在,如果您有兴趣知道幕后发生了什么,可以添加一些跟踪

| ( strace head -n 1; tail )

在你的第二个例子中:注意:抱歉为strace格式,我现在正在使用cygwin。

[...]
 24   35374 [main] head 1784 read: 51 = read(0, 0x22C700, 1024)

第一个head进程尝试通过读取一个大块(1024字节)来读取输入,然后可能在缓冲区中查找换行符。至少,这就是我实现它的方式。正如您所看到的,它处理了所有51个字符,因此下一个过程没有任何剩余。

在你的第一个例子中:这里的主要区别在于我们有无穷无尽的输入,所以即使第一个head会读取一个大块,也会留下第二个进程的输入。边界将是任意的,它取决于块大小,头的实现,如何实现fread(缓冲IO)等等。例如,在我的系统上,这是输出:

123456789
56789

答案 1 :(得分:7)

是的,head肯定会读取多行。它将进行缓冲I / O.从文件读取,它似乎是按行读取,但是从管道读取,它一次读取512字节。这与你所看到的一致。 3456789可能不是第二行,而是第52行。要试验这一点,请使用可以区分线而不是yes的内容。 cat somefile |效果很好。

答案 2 :(得分:3)

(这里的答案很晚。)

虽然existing answer解释了您观察到的原因,但您可以使用变通方法来获取预期输出

将输出管道输出到行缓冲区输出的内容:

$ yes 123456789 | { head -n 1; head -n 1; }
123456789
56789
$ yes 123456789 | grep --line-buffered . | { head -n 1; head -n 1; }
123456789
123456789

请注意,我使用了{ ... },即命令分组,与( ... )不同,它不会创建子shell。

答案 3 :(得分:1)

如果你想获得

123456789
123456789

然后你需要这样的东西:

yes 123456789 | head -2

(是循环直到管道断裂,头-2给你2行)

对于第二部分,它应该遵循以获得你想要的东西:)

echo -e "123456789\n123456789\n123456789\n123456789\n123456789\n" | head -2