J'essaie d'écrire un script qui sera exécuté dans un répertoire donné avec de nombreux sous-répertoires de niveau unique. Le script sera cd dans chacun des sous-répertoires, exécutera une commande sur les fichiers du répertoire et sortira cd pour continuer dans le répertoire suivant. Quelle est la meilleure façon de procéder?
for d in ./*/ ; do (cd "$d" && somecommand); done
La meilleure façon est de ne pas utiliser du tout cd
:
find some/dir -type f -execdir somecommand {} \;
execdir
est 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.
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 faire de sous-shell - elle suit simplement sa progression dans le Shell actuel en alternant $OLDPWD
et $PWD
. Quand vous cd -
le Shell échange la valeur de ces deux variables, essentiellement, car il change de répertoire. Il imprime également le nom de chaque répertoire car il y fonctionne sur stderr.
Je viens juste d'y jeter un deuxième coup d'œil et j'ai décidé que je pouvais faire mieux avec la gestion des erreurs. Il sautera un répertoire dans lequel il ne peut pas cd
- et cd
affichera un message expliquant pourquoi stderr - et il break
avec un code de sortie différent de zéro si votre command
ne s'exécute pas correctement ou si vous exécutez command
affecte en quelque sorte sa capacité à retourner dans votre répertoire d'origine - $OLDPWD
. Dans ce cas, il fait également un cd -
last - et écrit le nom du répertoire de travail actuel résultant dans stderr.
pushd subdir
# do stuff
popd
pushd/popd sont des commandes bash qui fournissent une pile de répertoires. Vous pouvez faire plusieurs pushd
s puis plusieurs popd
s et revenir là où vous avez commencé. Vous pouvez également manipuler la pile avec dirs
.
En tant que commande bash intégrée, la documentation se trouve dans la page de manuel bash (man 1 bash
et recherchez (/
) pour pushd, n
pour avancer dans les résultats de la recherche) ou utilisez help pushd
help popd
help dirs
.
for D in ./*; do
if [ -d "$D" ]; then
cd "$D"
run_something
cd ..
fi
done