Script Bash para loop com find e muitos diretórios

1

Eu estou escrevendo um script bash para fazer algum trabalho em um diretório que contém muitos (100.000 +) subdiretórios. Existe um limite pré-definido para quantos argumentos você pode passar para um loop for como o seguinte?

for dir in $(find . -type d)
do
  # My code
done

Estou preocupado que o script bork se o comando find retorna muitos diretórios.

    
por Magnus 05.10.2012 / 02:43

4 respostas

6

Não analise a saída, e apenas use shell globbing - é mais seguro e integrado ao shell. Os built-ins do shell como for não estão sujeitos ao mesmo limite de comprimento da lista de argumentos que os processos externos, pois nenhuma chamada faz exec* .

for dir in ./*/; do
    # ...
done
    
por 05.10.2012 / 02:44
3

Se você tem bash 4 , pode fazer algo recursivo como:

shopt -s globstar
for dir in **/; do echo "$dir"; done
    
por 05.10.2012 / 03:05
2

Eu não concordo com a resposta que você aceitou - você terá problemas de memória se usar $(find) , mesmo sem um exec presente.

Em vez disso, escreva como

find . -type d | while IFS= read -r dir
do
  # My code
done

(Nota: isto assume que não há nome de diretório contendo um caractere de nova linha).

Então você não precisará da memória temporária para armazenar a saída find como faria com a substituição do comando. Isso também funcionaria se o comando find ou outro comando nunca fosse terminado, por exemplo:

# will not work!
for line in $(yes) ; do echo "$line" ; done

# works
yes | while IFS= read -r line ; do echo "$line" ; done
    
por 05.10.2012 / 04:30
0

Não gere nomes de arquivos com uma substituição de comando: isso será interrompido se os nomes dos arquivos contiverem espaço em branco ou \[?* .

Com o bash ≥4, ksh93 ou zsh, é possível evitar a maioria dos usos de find que usam apenas -type d ou -name … usando predicados ** glob para corresponder subdiretórios em qualquer profundidade. No bash, execute shopt -s globstar primeiro. Em ksh, execute set -o globstar primeiro.

for dir in **/; do …; done

Portavelmente ou, nos casos em que você precisar de mais, use find … -exec … + ou find … -print0 | xargs -0 … . Essa abordagem tem o benefício adicional de executar find um pouco em paralelo com a ação nos arquivos, embora isso só se torne verdade para árvores de diretório grandes (pelo menos milhares de arquivos correspondentes). Você pode fazer com que find ou xargs executem um shell se precisar fazer mais do que executar um comando.

find -type d -exec sh -c 'for x in "$@"; do echo "$x"; done' _ {} +

(Esse _ é $0 no fragmento do shell, que não usamos.)

    
por 06.10.2012 / 23:05

Tags