web-dev-qa-db-fra.com

Effectuer une action dans chaque sous-répertoire en utilisant Bash

Je travaille sur un script qui doit exécuter une action dans chaque sous-répertoire d'un dossier spécifique.

Quel est le moyen le plus efficace d’écrire cela?

173
mikewilliamson
for D in `find . -type d`
do
    //Do whatever you need with D
done
164
Mike Clark

Une version qui évite de créer un sous-processus:

for D in *; do
    if [ -d "${D}" ]; then
        echo "${D}"   # your processing here
    fi
done

Ou, si votre action est une commande unique, ceci est plus concis:

for D in *; do [ -d "${D}" ] && my_command; done

Ou une version encore plus concise ( merci @enzotib ). Notez que dans cette version, chaque valeur de D aura un slash de fin:

for D in */; do my_command; done
256
kanaka

Le moyen le plus simple non récursif est:

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

Le / à la fin indique, n'utilise que des répertoires.

Il n'y a pas besoin de

  • trouver
  • awk
  • ...
91
d0x

Utilisez la commande find.

Dans GNU find, vous pouvez utiliser le paramètre -execdir:

find . -type d -execdir realpath "{}" ';'

ou en utilisant le paramètre -exec:

find . -type d -exec sh -c 'cd -P "$0" && pwd -P' {} \;

ou avec la commande xargs:

find . -type d -print0 | xargs -0 -L1 sh -c 'cd "$0" && pwd && echo Do stuff'

Ou en utilisant pour boucle:

for d in */; { echo "$d"; }

Pour la récursivité, essayez d’agrandir globbing (**/) à la place (activé par: shopt -s extglob).


Pour plus d'exemples, voir: Comment aller dans chaque répertoire et exécuter une commande? chez SO

14
kenorb

Pratique one-liners

for D in *; do echo "$D"; done
for D in *; do find "$D" -type d; done ### Option A

find * -type d ### Option B

L'option A est correcte pour les dossiers avec des espaces entre eux. En outre, généralement plus rapide car il n'imprime pas chaque mot d'un nom de dossier en tant qu'entité distincte.

# Option A
$ time for D in ./big_dir/*; do find "$D" -type d > /dev/null; done
real    0m0.327s
user    0m0.084s
sys     0m0.236s

# Option B
$ time for D in `find ./big_dir/* -type d`; do echo "$D" > /dev/null; done
real    0m0.787s
user    0m0.484s
sys     0m0.308s
12
Sriram Murali

find . -type d -print0 | xargs -0 -n 1 my_command

9
Paul Tomblin

Cela créera un sous-shell (ce qui signifie que les valeurs des variables seront perdues à la fermeture de la boucle while]:

find . -type d | while read -r dir
do
    something
done

Cela ne va pas:

while read -r dir
do
    something
done < <(find . -type d)

L'un ou l'autre fonctionnera s'il y a des espaces dans les noms de répertoire.

7
Dennis Williamson

Tu pourrais essayer:

#!/bin/bash
### $1 == the first args to this script
### usage: script.sh /path/to/dir/

for f in `find . -maxdepth 1 -mindepth 1 -type d`; do
  cd "$f"
  <your job here>
done

ou similaire...

Explication:

find . -maxdepth 1 -mindepth 1 -type d: Trouver uniquement les répertoires avec une profondeur maximale récursive de 1 (uniquement les sous-répertoires de $ 1) et une profondeur minimale de 1 (exclut le dossier en cours .)

5
Henry Dobson

la réponse acceptée se brisera sur les espaces blancs si les noms de répertoires en contiennent, et la syntaxe préférée est $() pour bash/ksh. Utiliser l'option GNU find-exec avec +; par exemple

find .... -exec mycommand +;#this is same as passing to xargs

ou utilisez une boucle while

find .... |  while read -r D
do
  ...
done 
4
ghostdog74