Kiedy plik wejściowy jest widoczny (jak czytanie ze zwykłego pliku) lub nie widoczny (jak czytanie z potoku), sed(i inne standardowe narzędzia) będą zachowywać się inaczej (przeczytaj INPUT FILESsekcję w tym linku ).
Cytat z dokumentu:
Kiedy standardowe narzędzie odczytuje widoczny plik wejściowy i kończy się bezbłędnie, zanim osiągnie koniec pliku, narzędzie musi upewnić się, że przesunięcie pliku w otwartym opisie pliku jest właściwie ustawione tuż za ostatnim bajtem przetworzonym przez narzędzie.
Więc w:
(sed '/y/ q'; echo aaa; cat) < test
sedwykonał qpolecenie uit przed osiągnięciem EOF, więc pozostawił przesunięcie pliku na początku zzzlinii, więc catmoże kontynuować drukowanie pozostałych linii (GNU sed nie jest zgodny z POSIX w niektórych warunkach, patrz poniżej).
Kontynuując od dokumentu:
W przypadku plików, których nie można zobaczyć, stan przesunięcia pliku w otwartym opisie pliku dla tego pliku jest nieokreślony
W takim przypadku zachowanie nie jest określone. Większość standardowych narzędzi, w tym sed, zużywa dane wejściowe w jak największym stopniu. Odczytuje yyylinię i quit bez przywracania przesunięcia pliku, więc nic nie pozostanie cat.
GNU sednie jest zgodne ze standardem, zależy od implementacji stdio systemu i wersji glibc:
$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa
Tutaj wynik uzyskano z Mac OSX 10.11.6, maszyn wirtualnych Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19, które są uruchomione na Openstack z backendem CEPH.
W tych systemach można użyć -uopcji, aby osiągnąć standardowe zachowanie:
(gsed -u '/y/ q'; echo aaa; cat) </tmp/test
a dla rury:
$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz
co prowadzi do strasznie nieefektywnej wydajności, ponieważ sedmusi czytać jeden bajt na raz. Częściowe wyjście z 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(w podpowłoce) może ponownie użyć deskryptora pliku w pierwszym przypadku, ponieważ stdin jest powiązany z prawdziwym plikiem. W drugim przypadku stdin pochodzi z potoku, a nie z prawdziwego pliku. Pamiętaj, że również(sed '/y/ q'; echo aaa; cat) < <(cat test)nie drukujezzz.