É possível aninhar um 'find -exec' dentro de outro 'find -exec'?

14

Algo parecido com o seguinte é o que eu estou procurando, mas meu código não funciona, não importa como eu escape {}e+ ;

find ./ -maxdepth 1 -type d -name '.*' -exec \
    find {} -maxdepth 1 -type f -name '*.ini' -exec \
        md5sum \{\} \\; \;

Depois de ver essa pergunta sobre o Unix - e - Linux , descobri que o código a seguir funciona, mas não está aninhando o achado como tal, e suspeito que haja uma maneira melhor de realizar esse trabalho específico.

find ./ -maxdepth 1 -type d -name '.*' \
-exec bash -c 'for x; do
    find "$x" -maxdepth 1 -type f -name "*.ini" \
    -exec md5sum \{\} \;; \
done' _ {} \+

Existe alguma maneira de aninhar find -execsem a necessidade de chamar uma concha (como acima), com todas as suas citações esquisitas e restrições de escape?

Ou isso pode ser feito diretamente em um único comando find, usando uma mistura de seus muitos parâmetros?

Peter.O
fonte
4
Embora possa ser possível fazer o que você está pedindo, quando as coisas ficam tão complexas, eu mudo para shell ou scripts Perl. Seu segundo trecho de código está praticamente fazendo isso, apenas com o script de shell embutido. Os one-liners heróicos são divertidos, mas são difíceis de entender e, portanto, difíceis de manter. A menos que este seja um acordo único no qual você, de alguma forma, acabe se tornando bom, não vejo uma boa razão para fazê-lo além do desafio intelectual.
Warren Young
1
@ Warren Young: Eu certamente não acho que o conceito seja complexo, mas suponho que você queira dizer que não há uma maneira simples de lidar find, mas se findnão pode fazer isso, por que é findtão reverenciado (?) Como a ferramenta? usar para encontrar arquivos? ... Eu descobri subseqüentemente que find ./ -maxdepth 2 -path '.*/*.ini' -type f -exec md5sum {} \+funciona bem na minha situação (a referência de jw013 -pruneme levou a isso na página de manual), mas me pergunto se é um método robusto (em gêneros). Eu realmente nunca usei find(em menos de um ano de Linux) como locatefiz quase tudo o que preciso, por isso é um território desconhecido.
Peter.O
1
O -pathteste é exatamente o que eu ia sugerir. Com isso, você deve ser capaz de fazer tudo o que você quer (não para o Ace Of Base de associação;))
rozcietrzewiacz

Respostas:

8

Eu tentaria usar uma única descoberta como:

find .*/ -maxdepth 1 -type f -name '*.ini' -execdir md5sum {} +

ou mesmo (não find, apenas globbing shell)

md5sum .*/*.ini

embora isso não tenha a -type fverificação, isso só funciona se você não tiver diretórios / arquivos que não terminem em .ini. Se você poderia usar

for x in .*/*.ini; do 
    if [ -f "$x" ]; then 
        md5sum "$x"
    fi
done

o que, no entanto, perderia a vantagem de precisar apenas de uma chamada md5sum.

Editar

Para um método geral e seguro de encadeamento find, você pode fazer algo como

find <paths> <args> -print0 | xargs -0 -I{.} find {.} <args for second find> [etc.]
jw013
fonte
Eu recebo um erro com a -f, e, em seguida, outro erro com (f?) -execdir.. Quando eu substituir -execdir com -exec, e / ou também substituindo md5sum com impressão, recebo nada ..
Peter.O
Obrigado, pela alternativa ... mas eu sou mais do que uma maneira de fazer isso usando find... Não é tanto que eu apenas queira que este exemplo seja resolvido, estou procurando informações sobre as maneiras de encontrar-fu .. Talvez haja mais penugem do que fu na busca .. (eu não sei, porque eu praticamente nunca a usei), e esta é a primeira situação em que eu realmente queria usá-la (na verdade, para arquivos de imagem) e o O recurso -exec que eu ouvi muito parece não ser tão poderoso quanto seu representante (?) alude a ... (+1 para as alternativas, no entanto) .. mas seu findexemplo simplesmente não funciona (ainda )
Peter.O
Eu recebo este erro para o findcomando: ... find: The relative path ~ / bin 'está incluído na variável de ambiente PATH, que é insegura em combinação com a ação -execdir de find. Por favor, remova essa entrada de $ PATH` .... Então, talvez funcione, mas devo dizer que venho tentando me livrar dessa ~ / bin há algum tempo ... agora vou precisar olhar sério para isso ... não sei onde o coloquei ... alguma idéia de onde possa estar à espreita; o ~/binem meu CAMINHO
Peter.O
Eu acho que o poder de findé melhor apreciado em situações que não podem ser feitas inteiramente com globs, mas como esse tipo de situação é raro, normalmente não preciso encontrar muito.
Jw013
Ok .. isso é um ponto interessante e bom (sobre o uso de globs) ...
Peter.O
2

Seu problema original não exige que a chamada seja encontrada recursivamente, mas suponho que não era esse o ponto.

Eu acredito que não é possível chamar find recursivamente da maneira que você deseja.

O seguinte não está chamando find recursivamente (ou aninhando, como é chamado), mas você não pode simplesmente pegar um conjunto de resultados da primeira localização e alimentá-lo com a segunda? É assim que eu instintivamente faria:

find `find ./ -maxdepth 1 -type d -name '.*'` \
    -maxdepth 1 -type f -name '*.ini' -exec md5sum {} \;

Você também pode usar xargspara executar a segunda localização.

Atualizar:

Eu gostaria de acrescentar que, como a maioria dos utilitários UNIX usa vários argumentos de nome de arquivo em vez de um, você geralmente pode evitar o seguinte -exec:

md5sum `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`

Ao aninhar backticks, basta adicionar barras invertidas \antes das internas.

Se imaginarmos que md5sumleva apenas um argumento de nome de arquivo, sempre podemos envolvê-lo em um forloop:

for f in `find \`find ./ -maxdepth 1 -type d -name '.*'\` -maxdepth 1 -type f -name '*.ini'`
do
    md5sum $f
done

Observe que isso se torna mais difícil se houver nomes de arquivos / diretórios iniciados -ou contendo um espaço. Os utilitários UNIX não funcionam bem com eles. Nesse caso ./, --é necessário adicionar ou citar.

Obviamente, o exemplo original não é bom, porque poderíamos fazer:

md5sum .*/*.ini
estalar
fonte
1
Você forneceu uma boa visão geral da situação, mas todos os findmétodos mostrados recebem um erro quando um arquivo / diretório contém espaços ... md5sum .*/*.iniFunciona bem ... Estou começando a ter a sensação geral de que * Warren Young * comentar sobre as coisas que ficam 'complexas' findacontece no início do jogo :), mas eu suponho que isso ocorra findquando os testes de condição forem mais complexos, mas no que diz respeito ao aninhamento -exec, deixei a ideia de lado, como parece existem maneiras mais simples de fazer isso .. (mas perl não é "simples" para mim (ainda) ...
Peter.O
0

Pelo menos eu consegui aninhar 2 comandos find:

find ~ -maxdepth 1 -type d -name '.*' -execdir \
    find {} -maxdepth 1 -type f -name '*.ini' \;

Mas não resolvi invocar outra chamada -exec (dir) - a partir daí.

Usuário desconhecido
fonte
Sim, esse é o meu problema exatamente :)
Peter.O
Sim, mas não aninhar 3 não é o mesmo que não aninhar :) :)
user unknown