La ragione per cui
tac file | grep foo | head -n 1
non si ferma alla prima partita è a causa del buffering.
Normalmente, head -n 1esce dopo aver letto una riga. Quindi grepdovrebbe 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 grepbufferizza. Cioè, non lo sta scrivendo fino a quando non si è accumulato abbastanza (4096 byte nel mio test con GNU grep).
Ciò significa che grepnon 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-bufferedche gli dice di scrivere le linee non appena vengono trovate, indipendentemente dal fatto che vada a un terminale o meno. Quindi grepuscirebbe sulla seconda linea che trova.
Ma con GNU greppuoi comunque usare -m 1come ha mostrato @terdon, il che è meglio quando esce alla prima partita.
Se la tua grepnon è la GNU grep, puoi usare sedo awkinvece. Ma tac essendo un comando GNU, dubito che troverai un sistema con tacdove grepnon è GNU grep.
tac file | sed "/$pattern/!d;q" # BRE
tac file | P=$pattern awk '$0 ~ ENVIRON["P"] {print; exit}' # ERE
Alcuni sistemi devono tail -rfare la stessa cosa di GNU tac.
Si noti che, per i file regolari (ricercabili) tace tail -rsono 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 tacsu file non regolari) .
Su sistemi in cui tacné nessuno dei due tail -rè disponibile, le uniche opzioni sono implementare manualmente la lettura all'indietro con linguaggi di programmazione come perlo 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.