web-dev-qa-db-fra.com

Comment puis-je parcourir uniquement les répertoires de bash?

J'ai un dossier avec des répertoires et des fichiers (certains sont cachés, commençant par un point).

for d in *; do
 echo $d
done

va parcourir tous les fichiers, mais je veux boucler uniquement via les répertoires. Comment je fais ça?

287
rubo77

Si vous devez sélectionner des fichiers plus spécifiques que seuls les répertoires, utilisez find et passez-le à while read:

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

Utilisation shopt -u dotglob pour exclure les répertoires cachés (ou setopt dotglob/unsetopt dotglob en zsh).

IFS= pour éviter de diviser les noms de fichiers contenant l'un des $IFS, par exemple: 'a b'

voir réponse AsymLabs ci-dessous pour plus d'options find


éditer:
Si vous devez créer une valeur de sortie à partir de la boucle while, vous pouvez contourner le sous-shell supplémentaire par cette astuce:

while IFS= read -r d; do 
    if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -Prune -type d)
24
rubo77

Vous pouvez spécifier une barre oblique à la fin pour correspondre uniquement aux répertoires:

for d in */ ; do
    echo "$d"
done
374
choroba

Vous pouvez tester avec -d:

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

C'est l'un des opérateurs de test de fichiers .

85
goldilocks

Attention, la solution de choroba, bien qu'élégante, peut provoquer un comportement inattendu si aucun répertoire n'est disponible dans le répertoire courant. Dans cet état, plutôt que de sauter la boucle for, bash exécutera la boucle exactement une fois où d est égal à */:

#!/usr/bin/env bash

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

Je recommande d'utiliser ce qui suit pour se protéger contre ce cas:

#!/usr/bin/env bash

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

Ce code parcourra tous les fichiers du répertoire courant, vérifiez si f est un répertoire, puis echo f si la condition retourne true. Si f est égal à */, echo $f ne s'exécutera pas.

34
emagdne

Vous pouvez utiliser pure bash pour cela, mais il est préférable d'utiliser find:

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

(trouver en plus comprendra des répertoires cachés)

12
rush

Ceci est fait pour trouver les répertoires visibles et cachés dans le répertoire de travail actuel, à l'exclusion du répertoire racine:

pour parcourir simplement les répertoires:

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

pour inclure des liens symboliques dans le résultat:

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

faire quelque chose pour chaque répertoire (à l'exclusion des liens symboliques):

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

pour exclure les répertoires cachés:

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

pour exécuter plusieurs commandes sur les valeurs retournées (un exemple très artificiel):

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

au lieu de "sh -c", vous pouvez également utiliser "bash -c", etc.

7
AsymLabs

Cela inclura le chemin complet dans chaque répertoire de la liste:

for i in $(find $PWD -maxdepth 1 -type d); do echo $i; done
3
user26053

Vous pouvez parcourir tous les répertoires, y compris les répertoires cachés (commençant par un point) sur une seule ligne et plusieurs commandes avec:

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

Si vous souhaitez exclure les liens symboliques:

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

note: en utilisant la liste */ .*/ fonctionne en bash, mais affiche également les dossiers . et .. en zsh il ne les affichera pas mais lancera une erreur s'il n'y a pas de fichier caché dans le dossier

Une version plus propre qui inclura les répertoires cachés et exclura ../ sera avec l'option dotglob:

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

( ou setopt dotglob en zsh)

vous pouvez désactiver le dotglob avec

shopt -u dotglob
3
rubo77

Utilisez find avec -exec pour parcourir les répertoires et appeler un fonction dans l'option exec:

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

Utilisation shopt -s dotglob ou shopt -u dotglob pour inclure/exclure les répertoires cachés

0
rubo77
ls -d */ | while read d
do
        echo $d
done
0
dcat

Cela répertorie tous les répertoires ainsi que le nombre de sous-répertoires dans un chemin donné:

for directory in */ ; do D=$(readlink -f "$directory") ; echo $D = $(find "$D" -mindepth 1 -type d | wc -l) ; done
0
pabloa98