web-dev-qa-db-fra.com

Renommez les fichiers et les répertoires de manière récursive sous ubuntu/bash

Je souhaite renommer tous les fichiers et répertoires contenant le mot "spécial" en "normal". Il convient de conserver la sensibilité à la casse pour que "Spécial" ne devienne pas "normal".

Comment puis-je faire cela dans bash récursivement? 

53
Tom

Essayez ceci (nécessite bash --version> = 4):

shopt -s globstar
rename -n 's/special/regular/' **

Supprimez le commutateur -n lorsque vos tests sont corrects

warning Il existe d'autres outils du même nom qui peuvent ou ne peuvent pas le faire, alors soyez prudent.

Si vous exécutez la commande suivante (GNU)

$ file "$(readlink -f "$(type -p rename)")"

et vous avez un résultat comme 

.../rename: Perl script, ASCII text executable

et ne contenant pas:

ELF

alors cela semble être le bon outil =)

Sinon, en faire la valeur par défaut (généralement déjà le cas) sur Debian et ses dérivés comme Ubuntu:

$ Sudo update-alternatives --set rename /path/to/rename

(remplacez /path/to/rename par le chemin de votre commande Perl's rename.


Si vous n'avez pas cette commande, recherchez votre gestionnaire de paquets pour l'installer ou faites-le manuellement


Last but not least, cet outil a été écrit à l'origine par Larry Wall, le père de Perl.

68
Gilles Quenot

Une solution utilisant find:

Pour renommer uniquement les fichiers :

find /your/target/path/ -type f -exec rename 's/special/regular/' '{}' \;

Pour renommer les répertoires uniquement :

find /your/target/path/ -type d -execdir rename 's/special/regular/' '{}' \+

Pour renommer les fichiers et les répertoires :

find /your/target/path/ -execdir rename 's/special/regular/' '{}' \+
88
speakr

Si l'installation d'un autre outil ne vous dérange pas, vous pouvez utiliser rnm :

rnm -rs '/special/regular/g' -dp -1 *

Il passera par tous les répertoires/sous-répertoires (à cause de -dp -1) et remplacera special par regular dans leurs noms.

5
Jahid

La réponse de @ speakr était l'indice pour moi.

Si vous utilisez -execdir pour transformer à la fois des fichiers et des répertoires, vous voudrez également supprimer -type f de l'exemple présenté. Pour l'épeler, utilisez:

find /your/target/path/ -execdir rename 's/special/regular/' '{}' \+

Pensez également à ajouter un indicateur g (global) à la regex si vous souhaitez remplacer toutes les occurrences de special par regular dans un nom de fichier donné et pas uniquement à la première occurrence. Par exemple:

find /your/target/path/ -execdir rename 's/special/regular/g' '{}' \+

transformera special-special.jpg en regular-regular.jpg. Sans l'indicateur global, vous obtiendrez regular-special.jpg.

FYI: GNU Rename n’est pas installé par défaut sur Mac OSX. Si vous utilisez le gestionnaire de paquets Homebrew , brew install rename remédiera à cela.

2
U007D

Pour ceux qui veulent juste renommer des répertoires, vous pouvez utiliser cette commande:

find /your/target/path/ -type d -execdir rename 's/special/regular/' '{}' \;

Le type de note est maintenant d pour répertoire et utilise -execdir.

Cependant, je n'ai pas réussi à savoir comment renommer les fichiers et les répertoires en un seul passage.

Quelqu'un a déjà fait remarquer qu’une fois le dossier racine renommé, il ne pouvait plus parcourir l’arborescence de fichiers. Il existe un commutateur -d disponible qui effectue une traversée en profondeur de bas en haut, de sorte que la racine serait renommée en dernier, je crois:

find -d /your/target/path/ -type d -execdir rename 's/special/regular/' '{}' \;

Depuis la page de manuel (man find):

 -d      Cause find to perform a depth-first traversal, i.e., directories are visited in post-order and all entries in a directory will be
         acted on before the directory itself.  By default, find visits directories in pre-order, i.e., before their contents.  Note, the
         default is not a breadth-first traversal.
0
LokMac

Voici une autre approche plus portable qui fait not s'appuyer sur la commande rename (car elle peut nécessiter des paramètres différents en fonction des distributions).

Il renomme récursivement les fichiers et les répertoires:

find . -depth -name "*special*" | \
while IFS= read -r ent; do mv $ent ${ent%special*}regular${ent##*special}; done

Ce qu'il fait

  • utilisez le paramètre find with -depth pour réorganiser les résultats en effectuant une traversée depth-first (c’est-à-dire que toutes les entrées d’un répertoire sont affichées avant le répertoire lui-même).
  • effectuez des substitutions de modèle pour modifier uniquement la dernière occurrence de regular dans le chemin.

De cette façon, les fichiers sont modifiés en premier, puis chaque répertoire parent. 

Exemple

Donner l'arbre suivant:

├── aa-special-aa
│   └── bb-special
│       ├── special-cc
│       ├── special-dd
│       └── Special-ee
└── special-00

Il génère ces commandes mv dans cet ordre particulier:

mv ./aa-special-aa/bb-special/special-cc ./aa-special-aa/bb-special/regular-cc
mv ./aa-special-aa/bb-special/special-dd ./aa-special-aa/bb-special/regular-dd
mv ./aa-special-aa/bb-special ./aa-special-aa/bb-regular
mv ./aa-special-aa ./aa-regular-aa
mv ./special-00 ./regular-00

Pour obtenir l'arbre suivant:

├── aa-regular-aa
│   └── bb-regular
│       ├── regular-cc
│       ├── regular-dd
│       └── Special-ee
└── regular-00
0
jyvet