Comment écrire un script bash qui parcourt chaque répertoire dans un parent_directory et exécute une commande dans chaque répertoire .
La structure des répertoires est la suivante:
parent_directory (le nom peut être n'importe quoi - ne suit pas un modèle)
- 001 (les noms de répertoire suivent ce modèle)
- 0001.txt (les noms de fichiers suivent ce modèle)
- 0002.txt
- 0003.txt
- 002
- 0001.txt
- 0002.txt
- 0003.txt
- 0004.txt
- 003
- 0001.txt
le nombre de répertoires est inconnu.
cd "$d"
serait mieux en ce sens qu'il transfère vers des situations où le caractère générique correspond aux fichiers dont les noms contiennent des espaces et / ou des métacaractères shell.for f in foo bar; do cat "$f"/*.txt; done >output
est fonctionnellement équivalent àcat foo/*.txt bar/*.txt >output
. Cependant,ls
est une commande qui produit une sortie légèrement différente selon la façon dont vous lui passez les arguments; de même, ungrep
ouwc
qui génère un nom de fichier relatif sera différent si vous l'exécutez à partir d'un sous-répertoire (mais souvent, vous voulez éviter d'entrer dans un sous-répertoire précisément pour cette raison).Cette réponse publiée par Todd m'a aidé.
Le
\( ! -name . \)
évite d'exécuter la commande dans le répertoire courant.la source
find FOLDER* -maxdepth 0 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;
-exec bash -c 'cd "$0" && pwd' {} \;
car certains répertoires contenaient des guillemets simples et des guillemets doubles.-mindepth 1
pwd
directement?disd(){find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c 'cd "{}" && "$@"' \;}
ne fonctionne pas.Si vous utilisez GNU
find
, vous pouvez essayer des-execdir
paramètres, par exemple:ou (selon le commentaire @gniourf_gniourf ):
Remarque: vous pouvez utiliser
${0#./}
au lieu de$0
pour fixer./
à l'avant.ou un exemple plus pratique:
Si vous souhaitez inclure le répertoire courant, c'est encore plus simple en utilisant
-exec
:ou en utilisant
xargs
:Ou un exemple similaire suggéré par @gniourf_gniourf :
Les exemples ci-dessus prennent en charge les répertoires avec des espaces dans leur nom.
Ou en affectant dans un tableau bash:
Modifiez le nom
.
de votre dossier spécifique. Si vous n'avez pas besoin d'exécuter récursivement, vous pouvez utiliser: à ladirs=(*)
place. L'exemple ci-dessus ne prend pas en charge les répertoires avec des espaces dans le nom.Ainsi, comme @gniourf_gniourf l'a suggéré, la seule façon correcte de mettre la sortie de find dans un tableau sans utiliser de boucle explicite sera disponible dans Bash 4.4 avec:
Ou pas une méthode recommandée (qui implique l' analyse de
ls
):L'exemple ci-dessus ignorerait le répertoire actuel (comme demandé par OP), mais il cassera sur les noms avec des espaces.
Voir également:
la source
find
dans un tableau sans utiliser de boucle explicite sera disponible dans Bash 4.4 avecmapfile -t -d '' dirs < <(find . -type d -print0)
. Jusque-là, votre seule option est d'utiliser une boucle (ou de reporter l'opération àfind
).dirs
tableau; vous en boucle pourrait surfind
la sortie « ( en toute sécurité) comme ceci:find . -type d -print0 | while IFS= read -r -d '' file; do ...; done
.IFS
,read
, il donne l'impression de complexité supplémentaire. Je vais devoir y réfléchir, il y a peut-être un moyen plus simple de le faire.IFS
etread
(comme vous le dites) devient une seconde nature au fur et à mesure que vous vous y habituez ... ils font partie des manières canoniques et idiomatiques d'écrire des scripts.find . -type d -execdir echo $(pwd)/{} ';'
ne fait pas ce que vous voulez (elle$(pwd)
est développée avantfind
même d'être exécutée)…Vous pouvez y parvenir en raccordant puis en utilisant
xargs
. Le hic, c'est que vous devez utiliser l'-I
indicateur qui remplacera la sous-chaîne de votre commande bash par la sous-chaîne passée par chacun desxargs
.Vous voudrez peut-être remplacer
pwd
par la commande que vous souhaitez exécuter dans chaque répertoire.la source
Si le dossier de niveau supérieur est connu, vous pouvez simplement écrire quelque chose comme ceci:
Sur le $ (JOUEZ AUSSI QUE VOUS VOULEZ); vous pouvez mettre autant de code que vous le souhaitez.
Notez que je n'ai pas "cd" sur aucun répertoire.
À votre santé,
la source
ls
" ici - vous pouvez simplement le faire à lafor dir in $YOUR_TOP_LEVEL_FOLDER/*
place.ls $dir
expressionla source
Alors que les doublures sont bonnes pour une utilisation rapide et sale, je préfère une version plus détaillée pour l'écriture de scripts. C'est le modèle que j'utilise qui prend en charge de nombreux cas extrêmes et vous permet d'écrire du code plus complexe à exécuter sur un dossier. Vous pouvez écrire votre code bash dans la fonction dir_command. Ci-dessous, dir_coomand implémente le balisage de chaque référentiel dans git à titre d'exemple. Le reste du script appelle dir_command pour chaque dossier du répertoire. L'exemple d'itération à travers un ensemble de dossiers donné est également inclus.
la source
Je ne comprends pas le formatage du fichier, car vous ne voulez parcourir que des dossiers ... Cherchez-vous quelque chose comme ça?
la source
vous pouvez utiliser
pour rechercher tous les fichiers / répertoires dans le répertoire courant de manière récurrente
Ensuite, vous pouvez diriger la sortie de la commande xargs comme ceci
la source
la source
cd
dans un sous-shell.cd
donc ce code ne fait rien d'utile.