executa o comando do find chamado por find

3

Existe uma maneira de chamar recursivamente?

Eu gostaria de procurar por arquivos que correspondam a um determinado padrão apenas em diretórios que correspondam a outro padrão.

Basicamente:

for each (sub)directory D matching "*.data"
do
  for each file F in directory D (with subdirs) matching "*.important.txt"
  do
    run command foo on F
  done
done

Agora, se eu deixar de fora o requisito mais interno ( execute o comando foo em F ), é bem simples:

find . -type d -name "*.data" \
     -exec find \{\} -type f -name "*.important.txt" \;

No entanto, não encontrei uma maneira de passar um comando para o interior find . Por exemplo. o seguinte imprime find: argumento faltando para '-exec' cada vez que o find interno é chamado:

 find . -type d -name "*.data" \
      -exec find \{\} -type f -name "*.important.txt" \
                 -exec "foo \{\} \;" \;

Qualquer solução deve ser compatível com posix (executável em um script /bin/sh ), esp. Eu não estou procurando por soluções que

  • envolva a descoberta interna em um script de shell separado
  • envolva o achado interno em uma função bash
por umläute 07.04.2016 / 16:29

2 respostas

4

Para executar find em seu próprio resultado, você pode usar o argumento -c para sh (ou bash ) para evitar que o comando outer find trate a parte interna {} especialmente. No entanto, você precisa passar o resultado da descoberta externa como um argumento para sh , que pode ser expandido com $0 :

find . -type d -name "*.data" \
      -exec sh -c 'find "$0" -type f -name "*.important.txt" -exec echo \{\} \;' \{\} \;

Nota: $0 deve ser cotado ( "$0" ) para evitar problemas com nomes de diretório que contenham espaços em branco.

Esta não é realmente uma solução "recursiva", porque não permite aninhamento arbitrariamente profundo sem algum escape, mas suporta os dois níveis de find -exec s solicitados no seu exemplo.

Se o seu exemplo é semelhante ao seu problema real, você também pode experimentar o argumento -path para encontrar:

find . -path '*.data/*important.txt'
    
por 07.04.2016 / 17:04
1

versão bash (não compatível com POSIX)

#!/bin/bash
find . -type d -name 'a *' -print0 \
    | while IFS= read -r -d '' dir ; do
        find "$dir" -type f -name "*.c" -exec echo \{\} \;
    done

Problemas:

  • read não possui o parâmetro -d em POSIX
  • find não possui -print0 parâmetro em POSIX

(má) versão sh (compatível com POSIX)

#!/bin/sh
# WARNING: while this will work on directory names with spaces,
#          it will break on directory names that contain newlines
find . -type d -name 'a *' -print \
    | while IFS= read -r dir ; do
        find "$dir" -type f -name "*.c" -exec echo \{\} \;
    done

Problema: Como afirmado no comentário, ele será quebrado em nomes de diretório contendo novas linhas. Você pode pensar que isso não é um problema realista, mas isso adiciona uma fragilidade desnecessária ao seu script. Talvez outro programa tenha um bug que crie um diretório, etc.

(melhor) versão sh

veja a resposta de Ian Robertson

Entre. Se você precisar que seus scripts sejam compatíveis com POSIX, é recomendável usar shellcheck . Por exemplo, ele notará que read -d não está definido no POSIX.

    
por 20.04.2016 / 17:56

Tags