Коли вхідний файл можна шукати (як читання з звичайного файлу) або не шукати (наприклад, читати з труби), sed
(та інші стандартні утиліти) будуть вести себе по-різному (Прочитайте INPUT FILES
розділ за цим посиланням ).
Цитата від doc:
Коли стандартна утиліта зчитує шуканий вхідний файл і закінчується без помилки до того, як він дійде до кінця файлу, утиліта повинна гарантувати, що зміщення файлу у відкритому описі файлу належним чином розміщене біля останнього байта, обробленого утилітою.
Так у:
(sed '/y/ q'; echo aaa; cat) < test
sed
виконується q
команда uit до досягнення EOF, тому вона залишає зсув файлу на початку zzz
рядка, тому cat
може продовжувати друкувати залишкові рядки (GNU sed не є POSIX сумісним у певних умовах, див. нижче).
І продовжуючи від doc:
Для файлів, які не можна знайти, стан зсуву файлу у відкритому описі цього файлу не визначено
У цьому випадку поведінка не визначено. Більшість стандартних інструментів, включають sed
, споживають вхід максимально. Він читає, що проходить yyy
рядок, і q
uit без відновлення зміщення файлу, тому нічого не залишається 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
.