Existe uma maneira de forçar o find
comando a parar logo após encontrar a primeira correspondência?
Existe uma maneira de forçar o find
comando a parar logo após encontrar a primeira correspondência?
Respostas:
Com o GNU ou FreeBSD find
, você pode usar o -quit
predicado:
find . ... -print -quit
O find
equivalente ao NetBSD :
find . ... -print -exit
Se tudo o que você fizer é imprimir o nome e supondo que os nomes dos arquivos não contenham caracteres de nova linha, você poderá:
find . ... -print | head -n 1
Isso não será interrompido find
após a primeira partida, mas possivelmente, dependendo do tempo e do buffer da segunda partida ou (muito) depois. Basicamente, find
será finalizado com um SIGPIPE quando ele tentar produzir algo enquanto head
já estiver ausente, porque já leu e exibiu a primeira linha de entrada.
Observe que nem todos os shells aguardam esse find
comando após o head
retorno. As implementações de shell Bourne e AT&T de ksh
(quando não interativas) e yash
(somente se esse pipeline for o último comando em um script) não o deixariam em execução em segundo plano. Se você preferir ver esse comportamento em qualquer shell, sempre pode alterar o acima para:
(find . ... -print &) | head -n 1
Se você estiver fazendo mais do que imprimir os caminhos dos arquivos encontrados, tente esta abordagem:
find . ... -exec sh -c 'printf "%s\n" "$1"; kill "$PPID"' sh {} \;
(substitua printf
pelo que você faria com esse arquivo).
Isso tem o efeito colateral de find
retornar um status de saída, refletindo o fato de que ele foi morto.
Na verdade, o uso do sinal SIGPIPE em vez de SIGTERM (em kill -s PIPE
vez de kill
) fará com que alguns shells fiquem mais silenciosos sobre a morte (mas ainda retornariam um status de saída diferente de zero).
if [[ $(find ... -print -quit) ]]; then ...
Ele apenas testa se há alguma coisa impressa.
$(…)
parte entre aspas, caso você esteja usando apenas colchetes ( [ … ]
).
[
é um comando padrão. Não é tanto esse comando que é horrível, mas a maneira como os projéteis tipo Bourne analisam as linhas de comando. [[...]]
é uma construção do ksh que possui problemas próprios em vários shells. Por exemplo, até recentemente [[ $(...) ]]
, não funcionava zsh
(você precisava [[ -n $(...) ]]
). Exceto em zsh
, você precisa de aspas [[ $a = $b ]]
, [[ =~ ]]
há diferenças incompatíveis entre implementações e até mesmo entre versões para o bash e vários bugs em alguns. Pessoalmente, eu prefiro [
.
...
? .
find . -name something -print -quit
Encerra a busca após a primeira correspondência após a impressão.
Termine a localização após uma quantidade específica de correspondências e imprima os resultados:
find . -name something -print | head -n 5
Surpreendentemente - a cabeça agora termina a sequência após 5 partidas, embora eu não saiba como ou por quê.
É muito fácil testar. Basta encontrar uma pesquisa na raiz, o que resultaria em milhares, talvez até mais correspondências, levando pelo menos um minuto ou mais. Porém, quando canalizado para "head", "find" terminará após a quantidade especificada de linhas definida no head (o cabeçote padrão mostra 10, use "head -n" para especificar as linhas).
Observe que isso terminará depois que "head -n" atingir a contagem de caracteres de nova linha especificada e, portanto, qualquer correspondência que contenha vários caracteres de nova linha contará de acordo.
Para fins de entretenimento, aqui está um gerador de busca preguiçoso no Bash. Este exemplo gera um anel sobre os arquivos no diretório atual. Leia o quanto você quiser kill %+
(talvez apenas 1)
#!/usr/bin/env bash
unset -v files n
trap 'kill "$x_PID"' EXIT
coproc x while :; do
find . -type f -maxdepth 1 -exec sh -c "$(</dev/fd/3)" _ {} +
done 4<&0 <<\EOF 3<&0 <&4-
for x; do
read -r _
printf '%s\0' "$x"
done
EOF
while
echo >&${x[1]}
IFS= read -rd '' -u "$x" 'files[n++]'
do
printf '%q ' "${files[@]}"
echo
sleep .2
done
grep também retorna se usado com o sinalizador -m
, portanto, com
find stuff | grep -m1 .
ele retornará após a primeira linha impressa por localização.
A diferença entre isso e find stuff -print -quit | head -1
é que, se a pesquisa for rápida o suficiente, o grep poderá não ser capaz de interromper o processo a tempo (embora isso não importe muito), enquanto que, se a pesquisa for longa, será possível encontrar muitas impressões desnecessárias. linhas.
isso funciona com o busybox find, embora, como o busybox grep também o tenha -m
, não seja realmente necessário
find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;
isso emitirá uma mensagem sobre o processo de localização que recebeu o sinal (geralmente) sigterm, mas essa saída pertence ao shell em execução, não ao comando find, para que não mexa na saída do comando, o que significa que pipes ou redirecionamentos produzirão apenas a linha correspondido por encontrar.