Ich habe eine Testdatei mit dem Namen 'test' erstellt, die Folgendes enthält:
xxx
yyy
zzz
Ich habe den Befehl ausgeführt:
(sed '/y/ q'; echo aaa; cat) < test
und ich bekam:
xxx
yyy
aaa
zzz
Dann bin ich gelaufen:
cat test | (sed '/y/ q'; echo aaa; cat)
und bekam:
xxx
yyy
aaa
Frage
sed
Liest und druckt, bis es auf eine Zeile mit 'y' stößt, und stoppt dann. Im ersten, aber nicht im zweiten Fall liest und druckt cat den Rest.
Kann jemand erklären, welches Phänomen hinter diesem Verhaltensunterschied steckt?
Ich habe auch bemerkt, dass es in Ubuntu 16.04 und Centos 6 so funktioniert, aber in Centos 7 gibt kein Befehl 'zzz' aus.
cat
(in der Subshell) der Dateideskriptor im ersten Fall wiederverwendet werden kann, da stdin an eine echte Datei gebunden ist. Im zweiten Fall stammt stdin aus einer Pipe und nicht aus einer echten Datei. Beachten Sie, dass auch(sed '/y/ q'; echo aaa; cat) < <(cat test)
nicht gedruckt wirdzzz
.(head -n1; head -n1) < test
undcat test | (head -n1; head -n1)
Antworten:
Wenn eine Eingabedatei gesucht werden kann (wie das Lesen aus einer regulären Datei) oder nicht gesucht werden kann (wie das Lesen aus einer Pipe),
sed
verhalten sich (und andere Standarddienstprogramme) anders (sieheINPUT FILES
Abschnitt in diesem Link ).Zitat aus dem doc:
Also in:
sed
ausgeführtq
es Datei am Anfang der Offset links uit vor dem Erreichen EOF gebiete, sozzz
Linie, socat
weiter die Linien bleiben Druck (GNU sed ist nicht POSIX - konform in einem gewissen Zustand, siehe unten).Und weiter aus dem Dokument:
In diesem Fall ist das Verhalten nicht angegeben. Die meisten Standardwerkzeuge, einschließlich
sed
, verbrauchen die Eingabe so weit wie möglich. Es liest dieyyy
Zeile durch und beendet sie,q
ohne den Dateiversatz wiederherzustellen, so dass nichts mehr übrig bleibtcat
.GNU
sed
ist nicht standardkonform, abhängig von der stdio-Implementierung des Systems und der glibc-Version:Hier wurde das Ergebnis von Mac OSX 10.11.6, virtuellen Maschinen Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19 erhalten, die auf Openstack mit CEPH-Backend ausgeführt werden.
Auf diesen Systemen können Sie die
-u
Option verwenden, um das Standardverhalten zu erreichen:und für Pfeife:
Dies führt zu einer schrecklich ineffizienten Leistung, da
sed
jeweils ein Byte gelesen werden muss. Eine Teilausgabe vonstrace
:quelle
sed
hängt das von der stdio-Implementierung des Systems ab. Auf GNU-Systemen (mit der GNU-Libc) ist GNUsed
kompatibel, und esexit()
wird nach Dateien gesucht, die von stdio verwaltet werden.sed
ist nicht kompatibel, mein Manjaro-Laptop hat die gleichesed
Version 4.2.2strace -f sh -c '{ sed "/y/q"; echo aaa; cat; } <test'
Zeigen Sie auf meinen virtuellen Maschinen, dass no ausgeführtlseek()
wurde, während in meinem Manjaro alseek()
zuvor aufgerufen wurdeexit_group()
.main() { char buf[999]; gets(buf); }'
Programm testen .