find -exec + vs find | xargs: qual escolher?

32

Eu entendo que o -execpode ter uma +opção para imitar o comportamento de xargs. Existe alguma situação em que você prefere um formulário ao outro?

Pessoalmente, prefiro a primeira forma, apenas para evitar o uso de um cachimbo. Eu acho que certamente os desenvolvedores de finddevem ter feito as otimizações apropriadas. Estou correcto?

rahmu
fonte

Respostas:

21

Você pode encadear chamadas para descobrir (uma vez, quando soube, que é possível, o que pode ser hoje). Obviamente, isso só é possível enquanto você permanecer em busca. Depois de canalizar para xargs, fica fora de escopo.

Pequeno exemplo, dois arquivos a.lst e b.lst:

cat a.lst
fuddel.sh
fiddel.sh

cat b.lst
fuddel.sh

Não há truque aqui - simplesmente o fato de que ambos contêm "fuddel", mas apenas um contém "fiddel".

Suponha que não sabíamos disso. Pesquisamos um arquivo que corresponde a 2 condições:

find -exec grep -q fuddel {} ";" -exec grep -q fiddel {} ";" -ls
192097    4 -rw-r--r--   1 stefan   stefan         20 Jun 27 17:05 ./a.lst

Bem, talvez você conheça a sintaxe do grep ou de outro programa para passar as duas strings como condição, mas esse não é o ponto. Todo programa que pode retornar verdadeiro ou falso, dado um arquivo como argumento, pode ser usado aqui - grep era apenas um exemplo popular.

E observe que você pode seguir find -exec com outros comandos find, como -ls ou -delete ou algo semelhante. Observe que essa exclusão não apenas remove o rm (remove arquivos), mas também remove o rmdir (remove os diretórios).

Essa cadeia é lida como uma combinação de comandos AND, desde que não seja especificado de outra forma (ou seja, com um -orswitch (e parens (que precisam ser mascarados))).

Portanto, você não está saindo da cadeia de busca, o que é útil. Não vejo nenhuma vantagem em usar -xargs, pois você deve ter cuidado ao passar os arquivos, o que é algo que a descoberta não precisa fazer - ele lida automaticamente com a passagem de cada arquivo como um argumento único para você.

Se você acredita que precisa de alguma máscara para encontrar aparelhos {} , sinta-se à vontade para visitar minha pergunta, que pede evidências. Minha afirmação é: você não.

Usuário desconhecido
fonte
3
Este post abriu meus olhos para uma nova maneira de usar find. Muito obrigado!
Rahmu
1
"Não vejo nenhuma vantagem em usar -xargs". Como -execagir xargs -P4para que três dos quatro núcleos não fiquem ociosos?
Damian Yerrick 25/10
1
@DamianYerrick: finalize o comando -exec não em ";" mas com um + (/ sinal de mais).
usuário desconhecido
25

O encaminhamento seguro de nomes de arquivos xargsrequer que você findsuporte a -print0opção e xargstenha a opção correspondente para lê-la ( --nullou -0). Caso contrário, os nomes de arquivos com caracteres não imprimíveis ou barras invertidas ou aspas ou espaço em branco no nome podem causar um comportamento inesperado. Por outro lado, find -exec {} +está na especificação POSIXfind , por isso é portátil e é tão seguro quanto find -print0 | xargs -0e definitivamente mais seguro que find | xargs. Eu recomendo nunca ficar find | xargssem -print0.

jw013
fonte
6
Uma exceção notável à portabilidade find … -exec … {} +é o OpenBSD, que só adquiriu esse recurso com a versão 5.1 lançada em 2012. Todos os BSDs possuem -print0há vários anos, mesmo o OpenBSD (apesar de resistir a esse recurso por um tempo também). O Solaris, por outro lado, adere aos recursos do POSIX, para que você obtenha -exec +e não -print0.
Gilles 'SO- stop be evil'
-print0é uma dor e, embora você possa argumentar que xargs --delimiter "\n"não é equivalente, nunca usei o primeiro depois de descobrir o último.
Sridhar Sarnobat
3
Não vejo como -0é mais doloroso do que isso --delimiter "\n".
Jw013
2
Além disso -0, o GNU xargsprecisa -revitar executar o comando se não houver entrada.
Stéphane Chazelas
2
Outro problema | xargs -r0 cmdé que cmdo stdin é afetado (dependendo da xargsimplementação, é /dev/nullou da tubulação.
Stéphane Chazelas
10

Se você usar o -exec ... ;formulário (lembrando-se de escapar do ponto-e-vírgula), estará executando o comando uma vez por nome de arquivo. Se você usar -print0 | xargs -0, execute vários comandos por nome de arquivo. Você definitivamente deve usar o -exec +formulário, que coloca vários arquivos em uma única linha de comando e é muito mais rápido quando um grande número de arquivos está envolvido.

Uma grande vantagem do uso xargsé a capacidade de executar vários comandos em paralelo xargs -P. Em sistemas com vários núcleos, isso pode proporcionar uma enorme economia de tempo.

Alexios
fonte
6
Você quis dizer em -Pvez de -p. Lembre- xargs -Pse de que não está no padrão POSIX find -exec {} +, o que é importante se você está buscando portabilidade.
jw013
@ Alexios Você não precisa escapar do sinal de mais, porque ele não tem um significado especial para o shell: find /tmp/ -exec ls "{}" +funciona muito bem.
Daniel kullmann 27/06/12
1
Corrente, é claro. Eu tenho escapado de tudo depois -execde tanto tempo (sou masoquista, nem uso aspas para escapar {}, sempre digito \{\}; não pergunto); tudo parece que deve ser escapado agora.
Alexios #
1
@Alexios: Se você encontrar um exemplo (exceto de masoquista) em que o mascaramento do aparelho é útil, forneça-o como resposta à minha pergunta aqui . Eu nunca vi um exemplo em find /tmp/ -exec ls {} +que não funcionaria.
usuário desconhecido
1
Para mim, essa é a memória muscular formada nos dias do SunOS 4. Como faço isso há anos, não percebi completamente quando bashcomecei a aceitar o aparelho literalmente. Tenho certeza de que pelo menos uma das conchas antigas que usei fazia ataques sibilantes se o aparelho não escapasse.
Alexios
8

Em relação ao desempenho, pensei que isso -exec … +seria simplesmente melhor porque é uma ferramenta única que faz todo o trabalho, mas uma parte da documentação do GNU findutil diz que -exec … +pode ser menos eficiente em alguns casos:

[find with -exec … +] pode ser menos eficiente do que alguns usos de xargs; por exemplo, xargspermite que novas linhas de comando sejam construídas enquanto o comando anterior ainda está em execução e permite que você especifique vários comandos para executar em paralelo. No entanto, a find ... -exec ... +construção tem a vantagem de ampla portabilidade. O GNU findutils não suportou ' -exec ... +' até a versão 4.2.12 [janeiro de 2005] ; uma das razões para isso é que ele já teve a -print0ação ' ' em qualquer caso.

Eu não tinha muita certeza do que isso significava, então perguntei no bate-papo onde derobert explicou como:

findprovavelmente poderia continuar pesquisando o próximo lote de arquivos enquanto ele -exec … +estiver em execução, mas não o faz.
find … | xargs …porque a descoberta é um processo diferente e continua em execução até o buffer do tubo ser preenchido

(Formatação feita por mim.)

Então tem isso. Mas se o desempenho realmente importa, você teria que fazer comparações realistas ou melhor, perguntar-se se você gostaria de usar o shell para esses casos.

Aqui neste site, acho melhor aconselhar as pessoas a usarem o -exec … +formulário sempre que possível, porque apenas porque é mais simples e pelos motivos mencionados nas outras respostas aqui (por exemplo, lidar com nomes de arquivos estranhos sem ter que pensar muito).

phk
fonte