Com loops for
Para iterar sobre os subdiretórios de um diretório, você pode usar um loop for
.
for dir in */; do
echo "Doing something in $dir"
done
O curinga */
expande para subdiretórios no diretório atual e para links simbólicos para diretórios. Diretórios cujo nome começa com .
(ou seja, diretórios que são arquivos de ponto) são omitidos. Se você quiser pular links simbólicos, pode fazê-lo explicitamente.
for dir in */; do
if [ -L "${dir%/}" ]; then continue; fi
echo "Doing something in $dir"
done
Para executar um comando em todos os arquivos no diretório, use o curinga *
. Mais uma vez, isso exclui os arquivos de ponto. Se o diretório estiver vazio, o curinga não será expandido.
for dir in */; do
if [ -L "${dir%/}" ]; then continue; fi
if (set -- "$dir"*; [ "$#" -ne 0 ]); then
somecommand -- "$dir"*
fi
done
Se você precisar chamar o comando separadamente para cada arquivo, use um loop aninhado. No snippet a seguir, eu uso [ -e "$file" ] || [ -L "$file" ]
para testar se o arquivo é um arquivo existente (excluindo links simbólicos quebrados) ou um link simbólico (quebrado ou não); essa condição só falha se "$file"
for um padrão de caractere curinga não expandido devido ao diretório estar vazio.
for dir in */; do
if [ -L "${dir%/}" ]; then continue; fi
for file in "$dir"*; do
if [ -e "$file" ] || [ -L "$file" ]; then
somecommand -- "$file"
fi
done
done
Se o comando precisar ter o subdiretório como seu diretório atual, existem duas maneiras de fazê-lo. Você pode chamar cd
antes e depois.
for dir in */; do
if [ -L "${dir%/}" ]; then continue; fi
if cd -- "$dir"; then
for file in *; do
if [ -e "$file" ] || [ -L "$file" ]; then
somecommand -- "$file"
fi
done
cd ..
fi
done
Isso tem a desvantagem de poder falhar em casos de borda, como o subdiretório que está sendo movido durante a execução do comando ou o processo não ter permissão para ser alterado no diretório-pai. Para evitar esses casos de borda, uma alternativa para cd ..
é executar o comando em um subshell. Um subshell duplica o estado do shell original, incluindo seu diretório atual, e o que acontece no subshell não afeta o processo original do shell.
for dir in */; do
if [ -L "${dir%/}" ]; then continue; fi
( cd -- "$dir" &&
for file in *; do
if [ -e "$file" ] || [ -L "$file" ]; then
somecommand -- "$file"
fi
done
)
fi
done
Com achado
Como você pode ver, lidar com casos não nominais não é tão fácil. Alguns destes são casos de borda que você não pode se preocupar, mas um diretório vazio é algo que você deve ser capaz de lidar. Existem maneiras mais fáceis de lidar com esses casos se você usar ksh, bash ou zsh; acima eu mostrei o código que funciona em sh simples (e que não lida com arquivos de ponto).
Outra maneira de enumerar arquivos e diretórios é o comando find
. Ele é projetado para percorrer árvores de diretórios de forma recursiva, mas você também pode usá-lo mesmo se não houver subdiretórios. Com o GNU ou FreeBSD find, ou seja, no Linux não integrado, Cygwin, FreeBSD ou OSX, existe uma maneira fácil de executar um comando em todos os arquivos em uma árvore de diretório:
find . ! -type d -execdir somecommand {} \;
Isso executa o comando em todos os arquivos que não são diretórios. Para executá-lo apenas em arquivos regulares (excluindo links simbólicos e outros tipos especiais de arquivos):
find . -type f -execdir somecommand {} \;
Se você deseja excluir os arquivos que estão diretamente no diretório de nível superior:
find . -mindepth 2 -type f -execdir somecommand {} \;
Se houver subdiretórios e você não quiser recorrer a eles:
find . -mindepth 2 -maxdepth 3 -type f -execdir somecommand {} \;