Como parar o comando find após a primeira correspondência?

115

Existe uma maneira de forçar o comando find a parar logo após encontrar a primeira correspondência?

    
por coffeMug 28.01.2013 / 21:52

4 respostas

133

Com o GNU ou FreeBSD find , você pode usar o predicado -quit :

find . ... -print -quit

O equivalente de find do NetBSD:

find . ... -print -exit

Se tudo o que você fizer é imprimir o nome e assumir que os nomes de arquivo não contêm caracteres de nova linha, você pode fazer:

find . ... -print | head -n 1

Isso não parará find após a primeira partida, mas possivelmente, dependendo do tempo e do buffer na segunda partida ou (muito) depois. Basicamente, find será terminado com um SIGPIPE quando ele tentar gerar algo enquanto head já tiver desaparecido, porque ele já leu e exibiu a primeira linha de entrada.

Observe que nem todos os shells aguardarão o comando find depois que head retornou. 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 preferir ver esse comportamento em qualquer shell, você sempre poderá alterar o acima para:

(find . ... -print &) | head -n 1

Se você estiver fazendo mais do que imprimindo os caminhos dos arquivos encontrados, tente essa 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, usar o sinal SIGPIPE em vez de SIGTERM ( kill -s PIPE em vez de kill ) fará com que alguns shells fiquem mais silenciosos sobre essa morte (mas ainda retornem um status de saída diferente de zero).

    
por 28.01.2013 / 22:03
10
find . -name something -print -quit

Termina a localização após o primeiro jogo após a impressão.

Encerra a localização após uma quantidade específica de correspondências e resultados de impressão:

find . -name something -print | head -n 5

Surpreendentemente, cabeça agora termina string após 5 partidas, embora eu não saiba como ou por quê.

É muito fácil testar. Apenas deixe encontrar a pesquisa a no root, o que resultaria em milhares, talvez ainda mais correspondências, durante pelo menos um minuto ou mais. Mas quando canalizado em "head" "find" terminará após a quantidade especificada de linhas definidas em head (cabeça padrão mostra 10, use "head -n" para especificar linhas).

Observe que isso terminará depois que "head -n" atingir a contagem de caractere de nova linha especificada e, portanto, qualquer correspondência que contiver vários caracteres de nova linha contará de acordo.

    
por 26.11.2014 / 14:31
2

Para fins de entretenimento, aqui está um gerador de localização preguiçosa no Bash. Este exemplo gera um anel sobre os arquivos no diretório atual. Leia quantos você quiser, então 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
#!/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%pre%' "$x"
done
EOF

while
    echo >&${x[1]}
    IFS= read -rd '' -u "$x" 'files[n++]'
do
    printf '%q ' "${files[@]}"
    echo
    sleep .2
done
' "$x" done EOF while echo >&${x[1]} IFS= read -rd '' -u "$x" 'files[n++]' do printf '%q ' "${files[@]}" echo sleep .2 done
    
por 28.01.2013 / 23:17
1

grep também retorna se usado com o sinalizador -m , portanto com

find stuff | grep -m1 .

retornará após a primeira linha impressa por find.

A diferença entre este e find stuff -print -quit | head -1 é que, se a pesquisa for rápida o suficiente, o grep pode não conseguir parar o processo a tempo (embora não seja realmente importante), enquanto que se a pesquisa for longa, poupará encontrar imprima muitas linhas desnecessárias.

isso funciona com o busybox find, embora o busybox grep também tenha -m não é realmente necessário

find /tmp/stuff -exec "sh" "-c" "eval 'echo {}; { kill \$PPID; }'" \;

isto irá mostrar uma mensagem sobre o processo de busca ter recebido o sinal (normalmente) sigterm, mas esta saída pertence ao shell em execução, não ao comando find para que não mexa com a saída do comando, significando que pipes ou redirecionamentos apenas a linha encontrada por find.

    
por 09.04.2018 / 13:11

Tags