Когда входной файл доступен для поиска (например, чтение из обычного файла) или недоступен для поиска (например, чтение из канала), sed
(и другие стандартные утилиты) будут вести себя по-другому (см. INPUT FILES
Раздел « Чтение » в этой ссылке ).
Цитата из документа:
Когда стандартная утилита считывает искомый входной файл и завершает работу без ошибки до того, как достигнет конца файла, утилита должна убедиться, что смещение файла в описании открытого файла правильно расположено сразу после последнего байта, обработанного утилитой.
Итак, в:
(sed '/y/ q'; echo aaa; cat) < test
sed
выполнил q
команду uit до достижения EOF, поэтому он оставил смещение файла в начале zzz
строки, поэтому cat
можно продолжить печать оставшихся строк (GNU sed не совместим с POSIX в некоторых условиях, см. ниже).
И продолжаем из дока:
Для файлов, которые нельзя найти, состояние смещения файла в описании открытого файла для этого файла не указано
В этом случае поведение не определено. Большинство стандартных инструментов, включающих, sed
будут потреблять ввод как можно больше. Он читает проход и передает yyy
строку q
без восстановления смещения файла, поэтому ничего не остается cat
.
GNU sed
не соответствует стандарту, зависит от реализации stdio системы и версии glibc:
$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa
Здесь результат был получен от Mac OSX 10.11.6, виртуальных машин Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19, которые работают на Openstack с бэкэндом CEPH.
В этих системах вы можете использовать -u
опцию для достижения стандартного поведения:
(gsed -u '/y/ q'; echo aaa; cat) </tmp/test
и для трубы:
$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz
что приводит к ужасно неэффективной производительности, потому что sed
приходится читать по одному байту за раз. Частичный вывод из strace
:
$ strace -fe read sh -c '{ sed -u "/y/q"; echo aaa; cat; } <test'
...
[pid 5248] read(3, "", 4096) = 0
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "\n", 1) = 1
xxx
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "\n", 1) = 1
yyy
...
cat
(в под-оболочке) может повторно использовать дескриптор файла в первом случае, потому что stdin связан с реальным файлом. Во втором случае stdin из канала, а не из реального файла. Обратите внимание, что также(sed '/y/ q'; echo aaa; cat) < <(cat test)
не печатаетzzz
.