web-dev-qa-db-fra.com

Renommer récursivement les fichiers (change extension) sous Linux

Comment renommer tous les fichiers d'un répertoire, de manière récursive, en changeant une extension de fichier pour une autre, en milliers de fichiers dans des milliers de sous-dossiers? Je vois beaucoup de commandes qui font presque ce que je veux, mais pas tout à fait.

find . -name "*.andnav" -exec rename .andnav .tile {} \;
syntax error at (eval 1) line 1, near "."

...

rename -nv 's/\.andnav$/\.tile/i' *.andnav
0.png.andnav renamed as 0.png.tile
21
endolith

Deviner

find . -name "*.andnav" -exec rename -v 's/\.andnav$/\.tile/i' {} \;
./0/0.png.andnav renamed as ./0/0.png.tile
./0/1.png.andnav renamed as ./0/1.png.tile
./1/0.png.andnav renamed as ./1/0.png.tile
./1/1.png.andnav renamed as ./1/1.png.tile

bien sûr, supprimez le -v quand vous le faites, sinon vous perdrez du temps à afficher tous les fichiers

22
endolith

Avec zsh:

autoload zmv
zmv -n '(**/)(*).andnav' '$1$2.tile'

Supprimez le -n pour effectuer le changement de nom.

13
Gilles

Quelque chose comme:

find . -name '*.andnav' -exec sh -c 'mv "$0" "${0%.andnav}.tile"' {} \;
13
cYrus

J'ai trouvé cette méthode est plus facile et plus facile à lire:

find . -name "*.andnav" | rename "s/\.andnav$/.tile/"

Au moins sur les dérivées Ubuntu, renommer prend une liste de fichiers de STDIN si aucun n’est sur la ligne de commande. Et cela peut être testé facilement avec:

find . -name "*.andnav" | rename -vn "s/\.andnav$/.tile/"

jusqu'à ce que vous obteniez le droit.

4
Bernd Wechner

Renommez les fichiers et les répertoires avec find -execdir | rename

Si vous voulez renommer les fichiers et les répertoires, pas simplement avec un suffixe, c'est un bon modèle:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find . -depth -execdir rename 's/findme/replaceme/' '{}' \;

L'option awesome -execdir insère un cd dans le répertoire avant d'exécuter la commande rename, contrairement à -exec.

-depth veille à ce que le changement de nom soit effectué en premier lieu sur les enfants, puis sur les parents, afin d'éviter d'éventuels problèmes avec des répertoires parent manquants.

-execdir est requis car le changement de nom ne fonctionne pas correctement avec les chemins d'entrée autres que les noms de base, par exemple. les échecs suivants:

rename 's/findme/replaceme/g' acc/acc

Le piratage PATH est requis car -execdir a un inconvénient très gênant: find est extrêmement avisé et refuse de faire quoi que ce soit avec -execdir si vous avez des chemins relatifs dans votre variable d'environnement PATH, par exemple. ./node_modules/.bin, échouant avec:

find: Le chemin relatif ‘./node_modules/.bin’ est inclus dans la variable d’environnement PATH, qui n’est pas sécurisée en combinaison avec l’action -execdir de find. Veuillez supprimer cette entrée de $ PATH

Voir aussi: https://askubuntu.com/questions/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-the-path/1109378#11093738

-execdir est un GNU find extension to POSIX . rename est basé sur Perl et provient du package rename. Testé sous Ubuntu 18.10.

Renommer la solution de contournement de lookahead

Si vos chemins d'entrée ne proviennent pas de find, ou si vous en avez assez du désagrément relatif des chemins, nous pouvons utiliser un préfixe Perl pour renommer en toute sécurité les répertoires comme suit:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

Je n'ai pas trouvé d'analogue pratique pour -execdir avec xargs: Xargs: change le répertoire de travail en chemin du fichier avant de l'exécuter?

Le sort -r est requis pour garantir que les fichiers viennent après leurs répertoires respectifs, car les chemins les plus longs suivent les plus courts avec le même préfixe.