Странная труба буферизует - PullRequest
3 голосов
/ 21 марта 2019

У меня есть файл, полный номеров файлов (начиная с 0)

$ cat in.del
0
1
2
....

Может кто-нибудь объяснить, что здесь происходит и где происходит буферизация, отличная от конвейера?Насколько я понимаю, оба head's fileno (stdin) должны смотреть прямо в конец чтения канала

$ cat in.del | ( head -n1 ; head -n1 )
0
60

Чем следующий код отличается от приведенного выше?

$ cat in.del | ( head -n10 ; head -n10 )
0
1
...
8
9
60
1861 # O_o
1862
1863
...
1868
1869

Это работает какожидается и показывает, что head сам не читает больше байтов, чем фактически записывает в его 'stdout:

$ ( head -n10 ; head -n10 ) < ./in.del
0
1
...
9
10
11
...
18
19

Очевидно, что что-то связанное с каналом происходит

Обновление

ОС: Ubuntu 18.04.1 LTS

Bash: версия 4.4.19 (1) -релиз (x86_64-pc-linux-gnu)

Обновление 2 В дополнение к фантастическому ответу @Barmar, больше о буферизации stdio

1 Ответ

4 голосов
/ 21 марта 2019

Что происходит, так это то, что stdio одновременно читает весь канал из канала, а размер буфера в Linux составляет 8K.

Затем head читает первые 10 строк из буфера, печатает их и завершает работу.

Следующая head начинает чтение из канала, где остановился последний, 8K байт в файл. Он читает эту строку и следующие 9 строк. 60, который вы видите - это конец 1860.

Причина, по которой он работает, как и ожидалось, в последнем случае, заключается в том, что head ищет конец последней строки, напечатанной перед выходом. Поиск не работает в трубе, так что это не имеет никакого эффекта. Но когда stdin является обычным файлом, поиск работает, и следующий процесс начинается с того места, где поиск устанавливает позицию файла.

Я вижу немного другие результаты на моем Mac. Размер буфера составляет 64 КБ, поэтому второй head начинается намного позже в файле. Он также не выполняет поиск назад до конца последней напечатанной строки перед выходом, поэтому версия с перенаправлением файла работает так же, как конвейер.

...