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 FILES
sekcję 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
sed
wykonał q
polecenie uit przed osiągnięciem EOF, więc pozostawił przesunięcie pliku na początku zzz
linii, więc cat
moż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 yyy
linię i q
uit bez przywracania przesunięcia pliku, więc nic nie pozostanie cat
.
GNU sed
nie 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ć -u
opcji, 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ż sed
musi 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
.