Como faço para percorrer apenas diretórios no bash?

203

Eu tenho uma pasta com alguns diretórios e alguns arquivos (alguns estão ocultos, começando com ponto).

for d in *; do
 echo $d
done

fará um loop através de todos os arquivos, mas eu quero fazer um loop apenas através dos diretórios. Como eu faço isso?

    
por rubo77 14.08.2013 / 17:43

12 respostas

16

Se você precisar selecionar arquivos mais específicos do que apenas diretórios, use find e passe para while read :

shopt -s dotglob
find * -prune -type d | while IFS= read -r d; do 
    echo "$d"
done

Use shopt -u dotglob para excluir diretórios ocultos (ou setopt dotglob / unsetopt dotglob em zsh).

IFS= para evitar a divisão de nomes de arquivos contendo um dos $IFS , por exemplo: 'a b'

veja Resposta do AsymLabs abaixo para mais opções find

editar:
Caso você precise criar um valor de saída dentro do loop while, você pode contornar o subshell extra por este truque:

while IFS= read -r d; do 
    if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -prune -type d)
    
por 22.10.2013 / 06:50
260

Você pode especificar uma barra no final para corresponder apenas aos diretórios:

for d in */ ; do
    echo "$d"
done
    
por 14.08.2013 / 17:46
62

Você pode testar com -d :

for f in *; do
    if [[ -d $f ]]; then
        # $f is a directory
    fi
done

Este é um dos operadores de teste de arquivos .

    
por 14.08.2013 / 17:59
21

Observe que a solução da choroba, embora elegante, pode provocar um comportamento inesperado se nenhum diretório estiver disponível no diretório atual. Nesse estado, em vez de pular o loop for , o bash executará o loop exatamente uma vez, em que d é igual a */ :

#!/usr/bin/env bash

for d in */; do
    # Will print */ if no directories are available
    echo $d
done

Eu recomendo usar o seguinte para proteger contra este caso:

#!/usr/bin/env bash

for f in *; do
    if [ -d ${f} ]; then
        # Will not run if no directories are available
        echo $f
    fi
done

Este código percorrerá todos os arquivos no diretório atual, verifique se f é um diretório e, em seguida, echo f se a condição retornar true. Se f for igual a */ , echo $f não será executado.

    
por 27.07.2015 / 01:54
10

Você pode usar o bash puro para isso, mas é melhor usar o find:

find . -maxdepth 1 -type d -exec echo {} \;

(encontrar adicionalmente incluirá diretórios ocultos)

    
por 14.08.2013 / 17:46
5

Isso é feito para localizar diretórios visíveis e ocultos no diretório de trabalho atual, excluindo o diretório raiz:

para apenas passar pelos diretórios:

 find -path './*' -prune -type d

para incluir links simbólicos no resultado:

find -L -path './*' -prune -type d

para fazer algo em cada diretório (excluindo links simbólicos):

find -path './*' -prune -type d -print0 | xargs -0 <cmds>

para excluir diretórios ocultos:

find -path './[^.]*' -prune -type d

para executar vários comandos nos valores retornados (um exemplo muito artificial):

find -path './[^.]*' -prune -type d -print0 | xargs -0 -I '{}' sh -c \
"printf 'first: %-40s' '{}'; printf 'second: %s\n' '{}'"

em vez de 'sh -c' também pode usar 'bash -c', etc.

    
por 21.10.2013 / 05:47
3

Você pode percorrer todos os diretórios, incluindo diretórios ocultos (começando com um ponto) em uma linha e vários comandos com:

for file in */ .*/ ; do echo "$file is a directory"; done

Se você deseja excluir links simbólicos:

for file in *; do 
  if [[ -d "$file" && ! -L "$file" ]]; then
    echo "$file is a directory"; 
  fi; 
done

nota: usando a lista */ .*/ funciona no bash, mas também exibe as pastas . e .. enquanto no zsh ele não mostrará estas, mas lançará um erro se não houver nenhum arquivo oculto no pasta

Uma versão mais limpa que incluirá diretórios ocultos e excluirá ../ será com a opção dotglob:

shopt -s dotglob
for file in */ ; do echo "$file is a directory"; done

(ou setopt dotglob no zsh)

você pode cancelar o "dotglob" com

shopt -u dotglob
    
por 22.10.2013 / 06:49
3

Isso incluirá o caminho completo em cada diretório da lista:

for i in $(find $PWD -maxdepth 1 -type d); do echo $i; done
    
por 22.10.2013 / 07:16
0

Use find com -exec para percorrer os diretórios e chamar uma função na opção exec:

dosomething () {
  echo "doing something with $1"
}
export -f dosomething
find -path './*' -prune -type d -exec bash -c 'dosomething "$0"' {} \;

Use shopt -s dotglob ou shopt -u dotglob para incluir / excluir diretórios ocultos

    
por 22.10.2013 / 08:26
0
ls -d */ | while read d
do
        echo $d
done
    
por 27.07.2015 / 03:55
0

Isso lista todos os diretórios junto com o número de subdiretórios em um determinado caminho:

for directory in */ ; do D=$(readlink -f "$directory") ; echo $D = $(find "$D" -mindepth 1 -type d | wc -l) ; done
    
por 26.12.2017 / 19:33
-3
ls -l | grep ^d

ou:

ll | grep ^d

Você pode defini-lo como um alias

    
por 11.09.2017 / 20:46