La raison pour laquelle
tac file | grep foo | head -n 1
ne s’arrête pas au premier match à cause de la mise en mémoire tampon.
Normalement, head -n 1
quitte après avoir lu une ligne. Donc, grep
devrait obtenir un SIGPIPE et quitter dès qu'il écrit sa deuxième ligne.
Mais ce qui se passe, c’est que parce que sa sortie n’est pas transmise à un terminal, grep
mémoire tampon. C'est-à-dire qu'il ne l'écrit pas tant qu'il n'a pas suffisamment accumulé (4096 octets dans mon test avec GNU grep).
Cela signifie que vous grep
ne quitterez pas avant d'avoir écrit 8192 octets de données, donc probablement pas mal de lignes.
Avec GNU grep
, vous pouvez le faire quitter plus tôt en utilisant le --line-buffered
mot qui lui dit d’écrire des lignes dès qu’elles sont trouvées, qu’elles soient ou non acheminées vers un terminal. Alors grep
serait alors sortir sur la deuxième ligne qu'il trouve.
Mais avec GNU de grep
toute façon, vous pouvez utiliser à la -m 1
place ce que @terdon a montré, ce qui est mieux car il se termine au premier match.
Si vous n’êtes grep
pas GNU grep
, vous pouvez utiliser sed
ou awk
remplacer. Mais tac
étant une commande GNU, je doute que vous trouviez un système avec tac
où grep
n’est pas GNU grep
.
tac file | sed "/$pattern/!d;q" # BRE
tac file | P=$pattern awk '$0 ~ ENVIRON["P"] {print; exit}' # ERE
Certains systèmes doivent tail -r
faire la même chose que GNU tac
.
Notez que, pour les fichiers normaux (à rechercher), tac
et qu'ils tail -r
sont efficaces car ils lisent les fichiers à l'envers, ils ne les lisent pas entièrement en mémoire avant de les imprimer en arrière (comme le ferait l'approche @ slm ou tac
des fichiers non réguliers) .
Sur les systèmes où ni tac
ni tail -r
sont disponibles, les seules options sont d'implémenter la lecture en arrière à la main avec des langages de programmation tels que perl
ou utiliser:
grep -e "$pattern" file | tail -n1
Ou:
sed "/$pattern/h;$!d;g" file
Mais ceux-ci signifient trouver toutes les correspondances et n'impriment que le dernier.