Я создал тестовый файл с именем «test», который содержит следующее:
xxx
yyy
zzz
Я запустил команду:
(sed '/y/ q'; echo aaa; cat) < test
и я получил:
xxx
yyy
aaa
zzz
Затем я побежал:
cat test | (sed '/y/ q'; echo aaa; cat)
и получил:
xxx
yyy
aaa
Вопрос
sed
читает и печатает, пока не встретит строку с 'y', затем остановится. В первом случае, но не во втором, кошка читает и печатает все остальное.
Может кто-нибудь объяснить, что явление стоит за этой разнице в поведении?
Я также заметил, что это работает в Ubuntu 16.04 и Centos 6, но в Centos 7 ни одна из команд не выводит «zzz».
cat
(в под-оболочке) может повторно использовать дескриптор файла в первом случае, потому что stdin связан с реальным файлом. Во втором случае stdin из канала, а не из реального файла. Обратите внимание, что также(sed '/y/ q'; echo aaa; cat) < <(cat test)
не печатаетzzz
.(head -n1; head -n1) < test
иcat test | (head -n1; head -n1)
Ответы:
Когда входной файл доступен для поиска (например, чтение из обычного файла) или недоступен для поиска (например, чтение из канала),
sed
(и другие стандартные утилиты) будут вести себя по-другому (см.INPUT FILES
Раздел « Чтение » в этой ссылке ).Цитата из документа:
Итак, в:
sed
выполнилq
команду uit до достижения EOF, поэтому он оставил смещение файла в началеzzz
строки, поэтомуcat
можно продолжить печать оставшихся строк (GNU sed не совместим с POSIX в некоторых условиях, см. ниже).И продолжаем из дока:
В этом случае поведение не определено. Большинство стандартных инструментов, включающих,
sed
будут потреблять ввод как можно больше. Он читает проход и передаетyyy
строкуq
без восстановления смещения файла, поэтому ничего не остаетсяcat
.GNU
sed
не соответствует стандарту, зависит от реализации stdio системы и версии glibc:Здесь результат был получен от Mac OSX 10.11.6, виртуальных машин Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19, которые работают на Openstack с бэкэндом CEPH.
В этих системах вы можете использовать
-u
опцию для достижения стандартного поведения:и для трубы:
что приводит к ужасно неэффективной производительности, потому что
sed
приходится читать по одному байту за раз. Частичный вывод изstrace
:источник
sed
это зависит от реализации stdio системы. В системах GNU (с GNU libc) GNUsed
будет совместимым, так какexit()
будет искать файлы, управляемые stdio.sed
не совместима, мой ноутбук manjaro имеет, все имеют ту жеsed
версию 4.2.2strace -f sh -c '{ sed "/y/q"; echo aaa; cat; } <test'
не показывают , что неlseek()
было выполнено, в то время как в моем manjarolseek()
была вызвана преждеexit_group()
.main() { char buf[999]; gets(buf); }'
программы.