Como você já está usando as extensões GNU ( -quit
, -H
, -m1
), é melhor usar a opção grep
do GNU -r
, junto com --line-buffered
, para gerar a saída corresponde assim que eles são encontrados, então é mais provável que seja morto de um SIGPIPE assim que ele escreve a 6ª linha:
grep -rHm1 --line-buffered pattern /path | head -n 5
Com find
, você provavelmente precisará fazer algo como:
find /path -type f -exec sh -c '
grep -Hm1 --line-buffered pattern "$@"
[ "$(kill -l "$?")" = PIPE ] && kill -s PIPE "$PPID"
' sh {} + | head -n 5
Ou seja, envolva grep
em sh
(você ainda deseja executar o mínimo de invocações de grep
, daí o {} +
), e tenha sh
matar seu pai ( find
) quando grep
morre de um SIGPIPE.
Outra abordagem poderia ser usar xargs
como uma alternativa para -exec {} +
. xargs
sai imediatamente quando um comando que ele gera morre de um sinal assim:
find . -type f -print0 |
xargs -r0 grep -Hm1 --line-buffered pattern |
head -n 5
( -r
e -0
são extensões do GNU). Assim que grep
escrever no canal quebrado, tanto grep
como xargs
sairão e find
sairá também da próxima vez que imprimir algo depois disso. A execução de find
em stdbuf -oL
pode fazer com que isso aconteça mais cedo.
Uma versão POSIX poderia ser:
trap - PIPE # restore default SIGPIPE handler in case it was disabled
RE=pattern find /path -type f -exec sh -c '
for file do
awk '\''
$0 ~ ENVIRON["RE"] {
print FILENAME ": " $0
exit
}'\'' < "$file"
if [ "$(kill -l "$?")" = PIPE ]; then
kill -s PIPE "$PPID"
exit
fi
done' sh {} + | head -n 5
Muito ineficiente, pois executa vários comandos para cada arquivo.