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?
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)
Vous pouvez spécifier une barre oblique à la fin pour correspondre uniquement aux répertoires:
for d in */ ; do
echo "$d"
done
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 .
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.
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)
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.
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
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
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
ls -d */ | while read d
do
echo $d
done
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