web-dev-qa-db-fra.com

Comment boucler les répertoires sous Linux?

J'écris un script en bash sous Linux et je dois passer en revue tous les noms de sous-répertoires d'un répertoire donné. Comment puis-je parcourir ces répertoires (et ignorer les fichiers normaux)?

Par exemple:
le répertoire donné est /tmp/
il a les sous-répertoires suivants: /tmp/A, /tmp/B, /tmp/C

Je veux récupérer A, B, C.

143
Erik Sapir
cd /tmp
find . -maxdepth 1 -mindepth 1 -type d -printf '%f\n'

Une brève explication: find trouve les fichiers (bien évidemment)

  • . est le répertoire courant, après le cd, il s’agit de /tmp (à mon humble avis, c’est plus souple que d’avoir /tmp directement dans la commande find. Vous n’avez qu’un seul emplacement, le cd, à modifier, si vous voulez plus d'actions dans ce dossier)

  • -maxdepth 1 et -mindepth 1 assurez-vous que find ne regarde réellement que dans le répertoire en cours et n'inclut pas '.' dans le résultat.

  • -type d ne cherche que des répertoires

  • -printf '%f\n imprime uniquement le nom du dossier trouvé (plus une nouvelle ligne) pour chaque résultat.

E voila!

119
Boldewyn

Jusqu'à présent, toutes les réponses utilisent find, alors voici l'une d'entre elles avec juste le shell. Pas besoin d'outils externes dans votre cas:

for dir in /tmp/*/     # list directories in the form "/tmp/dirname/"
do
    dir=${dir%*/}      # remove the trailing "/"
    echo ${dir##*/}    # print everything after the final "/"
done
403
ghostdog74

Vous pouvez parcourir tous les répertoires, y compris les répertoires masqués (commençant par un point) avec:

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

note: en utilisant la liste */ .*/ ne fonctionne avec zsh que s’il existe au moins un répertoire caché dans le dossier. En bash, il affichera également . et ..


Une autre possibilité pour bash d'inclure des répertoires cachés serait d'utiliser:

shopt -s dotglob;
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

Pour sortir uniquement le nom du répertoire de fin (A, B, C comme interrogé) dans chaque solution, utilisez ceci dans les boucles:

file="${file%/}"     # strip trailing slash
file="${file##*/}"   # strip path and leading slash
echo "$file is the directoryname without slashes"

Exemple (cela fonctionne aussi avec les répertoires contenant des espaces):

mkdir /tmp/A /tmp/B /tmp/C "/tmp/ dir with spaces"
for file in /tmp/*/ ; do file="${file%/}"; echo "${file##*/}"; done
39
rubo77

Fonctionne avec des répertoires contenant des espaces

Inspiré par Sorpigal

while IFS= read -d $'\0' -r file ; do 
    echo $file; ls $file ; 
done < <(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d -print0)

Message original (ne fonctionne pas avec des espaces)

Inspiré par Boldewyn : Exemple de boucle avec la commande find.

for D in $(find /path/to/dir/ -mindepth 1 -maxdepth 1 -type d) ; do
    echo $D ;
done
15
zpon
find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n"
7

La technique que j'utilise le plus souvent est find | xargs. Par exemple, si vous voulez que tous les fichiers de ce répertoire et de tous ses sous-répertoires soient lisibles par tout le monde, vous pouvez faire:

find . -type f -print0 | xargs -0 chmod go+r
find . -type d -print0 | xargs -0 chmod go+rx

L'option -print0 se termine par un caractère NULL au lieu d'un espace. L'option -0 divise son entrée de la même manière. C'est donc la combinaison à utiliser sur des fichiers avec des espaces.

Vous pouvez imaginer que cette chaîne de commandes prend chaque sortie de ligne avec find et la colle à la fin d'une commande chmod.

Si la commande que vous voulez exécuter en tant qu'argument au milieu plutôt qu'à la fin, vous devez être un peu créatif. Par exemple, je devais changer de répertoire et lancer la commande latemk -c. Alors j'ai utilisé (de Wikipedia ):

find . -type d -depth 1 -print0 | \
    xargs -0 sh -c 'for dir; do pushd "$dir" && latexmk -c && popd; done' fnord

Cela a pour effet de for dir $(subdirs); do stuff; done, mais est sans danger pour les répertoires avec des espaces dans leurs noms. De plus, les appels séparés à stuff sont effectués dans le même shell. C'est pourquoi, dans ma commande, nous devons revenir au répertoire actuel avec popd.

5
Matthew Leingang

find . -type d -maxdepth 1

2
Anonymous

une boucle minimale bash que vous pouvez créer (basée sur la réponse ghostdog74)

for dir in directory/*                                                     
do                                                                                 
  echo ${dir}                                                                  
done

compresser tout un tas de fichiers par répertoire

for dir in directory/*
do
  Zip -r ${dir##*/} ${dir}
done                                               
2
Harry Moreno