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.