Atravesse todos os subdiretórios e faça algo no shell script do Unix

17

Quero que meu script shell visite todos os subdiretórios em um diretório principal. Faça algo nos diretórios, envie a saída para um arquivo em spool e vá para o próximo diretório. Considere Dir principal = / tmp Sub dir = ABCD (quatro subdiretórios)

Ashish
fonte
2
OK, por favor, mostre seu script até agora. Qual parte está lhe causando problemas?
terdon

Respostas:

22

Use um forloop:

for d in $(find /path/to/dir -maxdepth 1 -type d)
do
  #Do something, the directory is accessible with $d:
  echo $d
done >output_file

Ele pesquisa apenas os subdiretórios do diretório /path/to/dir. Observe que o exemplo simples acima falhará se os nomes de diretório contiverem espaços em branco ou caracteres especiais. Uma abordagem mais segura é:

find /tmp -maxdepth 1 -type d -print0 |
  while IFS= read -rd '' dir; do echo "$dir"; done

Ou simplesmente bash:

for d in /path/to/dir/*; do
  if [ -d "$d" ]; then
    echo "$d"
  fi
done

(observe que, ao contrário do findque se pensa, também são considerados links simbólicos para diretórios e excluídos os ocultos)

caos
fonte
11
pelo menos aponte as limitações e riscos associados ao processamento da saída desse findtipo.
Stéphane Chazelas 27/02
Oi ... eu tentei executar abaixo o loop for d em $ (find / backup / ASHISH -maxdepth 1 -type d) do ls -l | awk '{print $ 9}' | grep CC * _ date +"%m%d20%Y"| xargs echo echo $ d
Ashish 27/02
Oi ... Eu tentei abaixo para loop. para d em $ (find / backup / ASHISH -maxdepth 1 -type d) do ls -l | awk '{print $ 9}' | grep CC * _ date +"%m%d20%Y"| xargs echo echo $ d O resultado esperado é ls -ltr de todos os subdiretórios . O loop acima não está funcionando #
2700 Ashish
1

Sou um bashnovato completo , mas um veterano da UN * X. Embora, sem dúvida, isso possa ser feito nos scripts de shell do Bash, nos velhos tempos costumávamos find [-maxdepth <levels>] <start-dir> -exec <command> ;fazer isso. Você pode fazer uma man findbrincadeira, talvez até que alguém lhe diga como fazê-la bash!

JonBrave
fonte
Estou muito lisonjeado por minha resposta "resumida" aqui ter recebido uma votação positiva. No entanto, por que a resposta do @chaos 'abaixo recebeu um voto negativo? (Como um novato neste fórum, não posso postar esse comentário contra a resposta dele, apenas contra a minha.) Sua segunda sugestão está correta para uma solução de script de shell e evita a sobrecarga de executar um findcomando externo .
JonBrave 27/02
Seu segundo é realmente correto. O primeiro falhará se os nomes de diretório contiverem espaços em branco ou caracteres especiais (barras invertidas, por exemplo). Veja a edição que fiz na resposta dele para a versão segura.
terdon
Concordo. Era a segunda resposta que eu estava elogiando.
31415 JonBrave
Eu sei, eu estava apenas explicando o voto negativo (que não fiz).
terdon
Eu fiz o elenco. A $(find...)coisa é má prática .
Stéphane Chazelas 27/02
1

Parece que você deseja os nomes de arquivos em cada um dos subdiretórios; o ls -l | awknão é suficiente robusta, para o que se esses nomes incluem espaços em branco e / ou novas linhas? O abaixo findfuncionaria mesmo para finds que não têm a -maxdepthoportunidade para eles:

find . ! -name . -type d -prune -exec sh -c '
   cd "$1" && \
   find "." ! -name . -prune  -type f
' {} {} \;

fonte
0

Eu tenho a solução. O comando find abaixo atende aos meus requisitos.

find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && ls -l |awk '{ print $9 }' |grep `date +"%m%d%Y"`|xargs echo" \;
Ashish
fonte
0

Também é possível usar ls, grep e tr

for dir in $(ls -1FA | grep / | tr -d /); do echo $dir/something; done

ls -1FA | grep / | tr -d / | while IFS= read -r TD; do echo $TD/something; done

du / sed também pode ser usado como seletor se o seu ls não possui as opções acima

du --max-depth=1 | sed -e 's/^.*\.\///' | grep -v '\.$'

Pode ser importante observar que esses exemplos retornam diretórios ocultos e excluem os diretórios pai e atual

JGurtz
fonte
11
(1)  lsgrava um arquivo por linha (o que a -1opção especifica) por padrão quando a saída padrão é um pipe (portanto, é supérfluo em suas respostas). (2) Analisar a saída de lsé uma péssima idéia - veja isto e isto . Sua primeira resposta falhará se os diretórios tiverem espaços (ou novas linhas) em seus nomes e tudo falhará se eles tiverem novas linhas em seus nomes. (3) Você deve sempre citar variáveis ​​do shell (por exemplo, "$dir") a menos que tenha um bom motivo para não fazê-lo e tenha certeza de que sabe o que está fazendo.
Scott
Bons pontos Scott. Deixando a resposta como, para muitos sistemas sem dirs nomeados de maneira grosseira, acho que ainda pode ser útil para os que estão fora.
JGurtz