The Unseen: A razão pela qual ele sai após cinco resultados quando canalizada para a cabeça -n 5 é porque a cabeça sai após cinco resultados. Quando a cabeça sai, o tubo se fecha e envia um sinal para o programa que o canaliza para terminar também. Desculpe por não responder diretamente a você, aparentemente você precisa de 50 reputação para responder.
Ruste
Respostas:
148
Com o GNU ou FreeBSD find, você pode usar o -quitpredicado:
find . ... -print -quit
O findequivalente 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 findapós a primeira partida, mas possivelmente, dependendo do tempo e do buffer da segunda partida ou (muito) depois. Basicamente, findserá finalizado com um SIGPIPE quando ele tentar produzir algo enquanto headjá estiver ausente, porque já leu e exibiu a primeira linha de entrada.
Observe que nem todos os shells aguardam esse findcomando após o headretorno. 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 printfpelo que você faria com esse arquivo).
Isso tem o efeito colateral de findretornar 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 PIPEvez de kill) fará com que alguns shells fiquem mais silenciosos sobre a morte (mas ainda retornariam um status de saída diferente de zero).
Caso alguém precise testar se algum arquivo corresponde aos predicados, parando assim que um é encontrado, no Bash e no GNU Find você pode fazer: if [[ $(find ... -print -quit) ]]; then ...Ele apenas testa se há alguma coisa impressa.
Tobia
@Tobia É melhor colocar a $(…)parte entre aspas, caso você esteja usando apenas colchetes ( [ … ]).
Phd #
@phk Exceto que eu não estou usando os colchetes simples (porque são horríveis), então não preciso usar aspas.
213 Tobia
2
@Tobia, [é 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 [.
Stéphane Chazelas
o que é ...? .
Kyb
11
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.
Também observei que esse 'programa termina após o término do processo de saída', mas não de forma consistente entre os shells. Acho que isso merece sua própria pergunta - felizmente para bash, a resposta já está no comportamento Bash: Head & Tail do StackOverflow com script bash . Isso fornece informações suficientes para concluir que se o programa termina ou continua a ser executado em segundo plano depende de sua resposta ao SIGPIPE - matar é o padrão.
sage
Eu quis dizer 'across * programs * / shells', mas aparentemente o unix.stackexchange.com prefere que eu registre isso como um segundo comentário, em vez de me permitir editar meu primeiro comentário (essa é uma decisão de política específica do site de stackexchange). Além disso, agora vejo que @Ruste comentou para este efeito, na parte superior, o que não me ajudou inicialmente desde que eu fui direto para respostas ...
sage
2
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
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.
Respostas:
Com o GNU ou FreeBSD
find
, você pode usar o-quit
predicado:O
find
equivalente ao NetBSD :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á:
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 enquantohead
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 ohead
retorno. As implementações de shell Bourne e AT&T deksh
(quando não interativas) eyash
(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:Se você estiver fazendo mais do que imprimir os caminhos dos arquivos encontrados, tente esta abordagem:
(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 dekill
) fará com que alguns shells fiquem mais silenciosos sobre a morte (mas ainda retornariam um status de saída diferente de zero).fonte
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 funcionavazsh
(você precisava[[ -n $(...) ]]
). Exceto emzsh
, 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[
....
? .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:
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.
fonte
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)fonte
grep também retorna se usado com o sinalizador
-m
, portanto, comele 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árioisso 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.
fonte