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?
for D in `find . -type d`
do
//Do whatever you need with D
done
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
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
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
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
find . -type d -print0 | xargs -0 -n 1 my_command
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.
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 .
)
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