Accédez à tous les répertoires, exécutez la commande sur les fichiers de ce répertoire et revenez au répertoire actuel précédent.

41

J'essaie d'écrire un script qui sera exécuté dans un répertoire donné avec plusieurs sous-répertoires à un seul niveau. Le script se place dans chacun des sous-répertoires, exécute une commande sur les fichiers du répertoire et se termine pour continuer dans le répertoire suivant. Quelle est la meilleure façon de procéder?

Quelque chose Jones
la source
1
Étant donné le niveau actuel d’information donné, je ne vois aucune pertinence pour youtube-dl.
HalosGhost

Réponses:

83
for d in ./*/ ; do (cd "$d" && somecommand); done
psusi
la source
12
Donc, puisque le répondeur a omis toute explication, je vais en tenter une. for d in ./*/démarre une boucle qui stocke chaque élément dans ./*/(une liste de fichiers / dossiers, dans ce cas) dans une variable $d. do (cd "$d" && somecommand);commence le corps de la boucle. À l'intérieur du corps, il commence un sous - shell et exécute les commandes cdet somecommand. Comme il s'agit d'un shell enfant, le shell parent (celui à partir duquel vous exécutez cette commande) conserve son CWD et d'autres variables d'environnement. doneferme simplement le corps de la boucle.
Qix
cette méthode fonctionne pour les sous-répertoires de répertoires:, for d in ./*/ ; do (cd "$d" && ls); donene fonctionnera pas. mais, for d in ./*/ ; do (cd "$d" && for d in ./*/ ; do (cd "$d" && ls); done ); donetravaillera. -Utilisez ls comme commande dans cet exemple.
Michael Dimmitt
-bash: cd: ./*/: No such file or directory
S. Tarık Çetin
15

Le meilleur moyen est de ne pas utiliser cddu tout:

find some/dir -type f -execdir somecommand {} \;

execdirest comme exec, mais le répertoire de travail est différent:

   -execdir command {} [;|+]
          Like   -exec,   but  the  specified  command  is  run  from  the
          subdirectory containing the matched file, which is not  normally
          the  directory  in  which  you  started  find.  This a much more
          secure  method  for  invoking  commands,  as  it   avoids   race
          conditions  during resolution of the paths to the matched files.

Ce n'est pas POSIX.

muru
la source
Est-ce que cela fonctionne avec des alias? J'en ai un pour télécharger certains fichiers, mais il ne le reconnaît pas lorsque je tape find * /. Link -type f -execdir md $ (cat .link) {} \;
Quelque chose Jones
@SomethingJones non, findexécute ces commandes, de sorte qu'il ne soit pas au courant des alias. Quel est mdet est le .linkrépertoire?
muru
.link est un fichier texte contenant l'URL à télécharger. md est un alias à wget avec un groupe de drapeaux. Y a-t-il un moyen de le rendre conscient des alias?
Quelque chose Jones
@SomethingJones Pour votre cas d'utilisation particulier, dans bash: find . -type f -iname '*.link' -execdir ${BASH_ALIASES[md]} -i {} \;Vous n'avez pas besoin de faire catavec wget, qui a un -idrapeau pour lire une URL à partir d'un fichier. En outre, cela diffère quelque peu de votre question initiale (car vous semblez ne vous intéresser qu'aux fichiers nommés .linket non aux autres fichiers éventuellement présents).
muru
Savez-vous comment faire cela avec zsh? J'ai essayé ce que vous m'avez donné et j'obtiens une erreur "Mauvaise substitution". Aussi, comment pourrais-je extraire le contenu du fichier .link? Je sais que je n'en ai pas besoin dans ce cas, mais j'imagine que je le ferai bientôt.
Quelque chose Jones
2
cd -P .
for dir in ./*/
do cd -P "$dir" ||continue
   printf %s\\n "$PWD" >&2
   command && cd "$OLDPWD" || 
! break; done || ! cd - >&2

La commande ci-dessus n'a pas besoin de créer de sous-shell. Elle suit simplement sa progression dans le shell actuel en alternant $OLDPWDet $PWD. Lorsque cd -le shell échange la valeur de ces deux variables, en gros, il change de répertoire. Il affiche également le nom de chaque répertoire lorsqu’il fonctionne pour stderr.

J'y ai jeté un deuxième coup d'œil et j'ai décidé que je pourrais faire un meilleur travail avec la gestion des erreurs. Il sautera un répertoire dans lequel il ne peut pas cd- et cdaffichera un message expliquant pourquoi stderr - et breakun code de sortie différent de zéro si votre programme commandne s'exécute pas correctement ou si son exécution commandaffecte sa capacité à retourner dans votre répertoire d'origine. - $OLDPWD. Dans ce cas, il effectue également un cd -dernier et écrit le nom du répertoire de travail actuel résultant dans stderr.

Mikeserv
la source
1
for D in ./*; do
    if [ -d "$D" ]; then
        cd "$D"
        run_something
        cd ..
    fi
done
Kirill
la source