Ich möchte eine Datei ansehen, bis etwas Text erscheint
Ich habe diese Antwort gefunden:`tail -f` bis Text gesehen wird
aber als ich es auf Ubuntu ausprobiert habe, wird es nicht beendet:
$ echo one > test.txt
$ echo two >> test.txt
$ echo three >> test.txt
$ echo four >> test.txt
$ cat test.txt | sed '/w/ q'
one
two
$
funktioniert wie erwartet. jedoch, wenn ich versuche, die Datei zu tailsieren
$ tail -f test.txt | sed '/w/ q'
one
two
es geht nie aus. Endstück stoppt nicht, obwohl das Rohr gebrochen ist.
Weiß jemand, wie man tail
macht beenden, wenn sed
Ausgänge?
Akzeptierte Antwort:
Es sind die gleichen Dinge wie in:
- Wie kann ich beim Schließen der Pipe vorzeitig aussteigen?
- Grep langsam zum Beenden, nachdem eine Übereinstimmung gefunden wurde?
- Finde Ausgabe begrenzen UND Signal 13 vermeiden
In:
cmd1 | cmd2
Ihre Shell wartet zufällig bis cmd1
wird auch nach cmd2
beendet ist bereits beendet. Das ist nicht bei allen Schalen der Fall. Einige wie die Bourne- oder Korn-Shell zum Beispiel nicht.
Wenn cmd2
Stirbt die Pipe auf cmd1
’s stdout wird kaputt , aber das beendet cmd1
nicht sofort.
cmd1
wird beendet, wenn es das nächste Mal versucht, in diese Pipe zu schreiben. Es erhält dann ein SIGPIPE, dessen Standardaktion darin besteht, den Prozess zu beenden.
Mit cmd1
==tail -f file
und cmd2
==sed /w/q
, tail -f
liest die letzten 10 Zeilen der Datei und schreibt sie nach stdout (die Pipe), normalerweise in einem Stück, es sei denn, die Zeilen sind wirklich groß und warten darauf, dass mehr Text an file
angehängt wird .
sed
, das gleichzeitig ausgeführt wird, wartet auf Eingaben auf seiner stdin, liest sie, verarbeitet sie Zeile für Zeile und beendet sich, wenn es eine Zeile gibt, die w
enthält .
Sobald (oder möglicherweise mit einer Verzögerung von einer Zeile mit etwas sed
Implementierung), wenn es diese Zeile findet, wird es beendet, aber zu diesem Zeitpunkt tail
bereits alles in die Pipe geschrieben hat, was sie schreiben musste, also erhält sie kein SIGPIPE, es sei denn, der Datei wird später zusätzlicher Text hinzugefügt (an diesem Punkt wird sie das fatale write()
ausführen ).
Wenn Sie cmd1
wollten zu beenden, sobald cmd2
beendet wird, brauchen Sie etwas, um es einmal zu beenden cmd2
endet. Wie bei:
sh -c 'echo "$$"; exec tail -f test.txt' | {
IFS= read pid
sed /w/q
kill -s PIPE "$pid"
}
Oder mit bash
:
{ sed /w/q; kill -s PIPE "$!"; } < <(exec tail -f text.txt)
2020 bearbeiten
Wie von @user414777 angemerkt, ist seit Version 8.28 die GNU-Implementierung von tail
, im Follow-Modus, fragt jetzt nicht nur nach neuen Daten in der/den Datei(en), die es überwacht, sondern prüft auch, ob seine stdout zu einer kaputten Pipe wird und dann sofort beendet wird (oder innerhalb einer Sekunde, wenn notify wird nicht verwendet), was die obigen Umgehungen überflüssig macht.
Beachten Sie jedoch, dass nur GNU tail
führt diese Art der Verarbeitung durch, keine andere Implementierung von tail
(AFAIK) und kein anderes Dienstprogramm (auch nicht die GNU-Implementierungen).
Also, während:
tail -f file | head -n1
Wird nach einer Zeile beendet,
tail -f file | tr '[:lower:]' '[:upper:]' | head -n1
zum Beispiel nicht unbedingt als tr
wird nicht überwachen, ob seine stdout zu einer defekten Pipe wird, und stirbt daher nur, wenn es schreibt etwas dort, nachdem die Pipe wie üblich gebrochen ist (und nur an diesem Punkt wird GNU tail -f
wird beendet).