La ragione per cui
tac file | grep foo | head -n 1
non si ferma alla prima partita è a causa del buffering.
Normalmente, head -n 1
esce dopo aver letto una riga. Quindi grep
dovrebbe ottenere un SIGPIPE ed uscire non appena scrive la sua seconda riga.
Ma ciò che accade è che, poiché il suo output non sta andando a un terminale, lo grep
bufferizza. Cioè, non lo sta scrivendo fino a quando non si è accumulato abbastanza (4096 byte nel mio test con GNU grep).
Ciò significa che grep
non uscirà prima che abbia scritto 8192 byte di dati, quindi probabilmente un bel po 'di righe.
Con GNU grep
, puoi farlo uscire prima usando ciò --line-buffered
che gli dice di scrivere le linee non appena vengono trovate, indipendentemente dal fatto che vada a un terminale o meno. Quindi grep
uscirebbe sulla seconda linea che trova.
Ma con GNU grep
puoi comunque usare -m 1
come ha mostrato @terdon, il che è meglio quando esce alla prima partita.
Se la tua grep
non è la GNU grep
, puoi usare sed
o awk
invece. Ma tac
essendo un comando GNU, dubito che troverai un sistema con tac
dove grep
non è GNU grep
.
tac file | sed "/$pattern/!d;q" # BRE
tac file | P=$pattern awk '$0 ~ ENVIRON["P"] {print; exit}' # ERE
Alcuni sistemi devono tail -r
fare la stessa cosa di GNU tac
.
Si noti che, per i file regolari (ricercabili) tac
e tail -r
sono efficienti perché leggono i file all'indietro, non stanno solo leggendo il file completamente in memoria prima di stamparlo all'indietro (come farebbe l' approccio di @ slm sed o tac
su file non regolari) .
Su sistemi in cui tac
né nessuno dei due tail -r
è disponibile, le uniche opzioni sono implementare manualmente la lettura all'indietro con linguaggi di programmazione come perl
o utilizzare:
grep -e "$pattern" file | tail -n1
O:
sed "/$pattern/h;$!d;g" file
Ma quelli significano trovare tutte le partite e stampare solo l'ultima.