Voglio guardare un file finché non appare un po' di testo
Ho trovato questa risposta:`tail -f` fino a quando non viene visualizzato il testo
ma quando l'ho provato su Ubuntu, non esce:
$ echo one > test.txt
$ echo two >> test.txt
$ echo three >> test.txt
$ echo four >> test.txt
$ cat test.txt | sed '/w/ q'
one
two
$
funziona come previsto. tuttavia quando provo a pedinare il file
$ tail -f test.txt | sed '/w/ q'
one
two
non esce mai. la coda non si ferma anche se il tubo è rotto.
Qualcuno sa come creare tail
esci quando sed
esce?
Risposta accettata:
Sono le stesse cose di:
- Come uscire presto alla chiusura del tubo?
- Grep lento per uscire dopo aver trovato una corrispondenza?
- limita l'output di ricerca E evita il segnale 13
In:
cmd1 | cmd2
La tua shell aspetta fino a cmd1
termina anche dopo cmd2
è già terminato. Non è il caso di tutte le conchiglie. Alcuni come la shell Bourne o Korn, per esempio, non lo fanno.
Quando cmd2
dies, la pipe su cmd1
Lo stdout di 's diventa rotto , ma ciò non termina cmd1
all'istante.
cmd1
terminerà la prossima volta che proverà a scrivere su quella pipe. Riceverà quindi un SIGPIPE la cui azione predefinita è terminare il processo.
Con cmd1
==tail -f file
e cmd2
==sed /w/q
, tail -f
leggerà le ultime 10 righe del file e le scriverà su stdout (la pipe), in genere in un blocco a meno che le righe non siano davvero grandi e stia lì ad aspettare che venga aggiunto più testo a file
.
sed
, che viene eseguito contemporaneamente, attenderà l'input sul suo stdin, lo leggerà, lo elaborerà riga per riga e chiuderà se c'è una riga che contiene w
.
Non appena (o eventualmente con un ritardo di una riga con alcuni sed
implementazione) quando trova quella riga, esce, ma in quel momento, tail
ha già scritto nella pipe tutto ciò che aveva per SCRIVERE, quindi non riceverà un SIGPIPE a meno che non venga aggiunto del testo aggiuntivo in seguito al file (a quel punto eseguirà il fatale write()
).
Se vuoi cmd1
per terminare non appena cmd2
termina, avresti bisogno di qualcosa per ucciderlo una volta cmd2
termina. Come con:
sh -c 'echo "$$"; exec tail -f test.txt' | {
IFS= read pid
sed /w/q
kill -s PIPE "$pid"
}
O con bash
:
{ sed /w/q; kill -s PIPE "$!"; } < <(exec tail -f text.txt)
Modifica 2020
Come notato da @user414777, dalla versione 8.28, l'implementazione GNU di tail
, nelle modalità segui, ora non solo esegue il polling dei nuovi dati nei file che monitora, ma controlla anche se il suo stdout diventa una pipe rotta ed esce immediatamente (o entro un secondo se inotify non viene utilizzato), rendendo superflui i lavori sopra descritti.
Tuttavia, nota che solo GNU tail
esegue questo tipo di elaborazione, non qualsiasi altra implementazione di tail
(AFAIK), e non qualsiasi altra utilità (nemmeno le implementazioni GNU).
Quindi, mentre:
tail -f file | head -n1
Uscirà dopo una riga,
tail -f file | tr '[:lower:]' '[:upper:]' | head -n1
per esempio non sarà necessariamente come tr
non controllerà se il suo stdout diventa un tubo rotto, quindi morirà solo se scrive qualcosa lì dopo che la pipe si è rotta come al solito (ed è solo a quel punto che GNU tail -f
uscirà).