Comment changer les noms de tous les répertoires / fichiers contenant une chaîne spécifique sur Linux

J’ai un répertoire dans lequel je souhaite remplacer tous les noms de répertoires et fichiers par un nom différent. Par exemple, ma structure de répertoire est

./mydir_ABC/ ./mydir_ABC/myfile_ABC.txt ./mydir_ABC/otherdir_ABC/ 

et je veux le faire par exemple

 ./mydir_DEF/ ./mydir_DEF/myfile_DEF.txt ./mydir_DEF/otherdir_DEF/ 

j’utilise

 find . -type 'f' -name '*ABC*' find . -type 'd' -name '*ABC*' 

pour obtenir une liste de tous les répertoires et fichiers pertinents qui contiennent ma chaîne dans leurs noms. Comment puis-je le diriger vers une autre commande qui changera réellement les noms de répertoire et les noms de fichiers? (Je veux pouvoir écraser si le fichier ou le répertoire existe déjà.)

Recherchez la commande rename(1) . Il existe différentes variantes, mais elles prennent toutes en charge un certain renommage basé sur des expressions régulières. La version que j’utilise (basée sur le code de la première édition du Perl ‘Camel Book’) serait utilisée comme:

 rename 's%ABC%DEF%g' ... 

Ou, pour votre exemple:

 find . -print0 | xargs -0 rename s/ABC/DEF/g 

Ou, pour éviter les problèmes avec les noms de chemin changeant pendant que vous traversez la structure de répertoire, faites d’abord les noms de répertoires, puis les fichiers (comme dans la question):

 find . -type d -print0 | xargs -0 rename s/ABC/DEF/g find . -type f -print0 | xargs -0 rename s/ABC/DEF/g 

Il est toujours possible de renommer les répertoires au fur et à mesure (car une fois que vous avez renommé ./ABC en ./DEF , vous ne pouvez plus renommer ./ABC/subABC/ en ./DEF/subDEF car le répertoire est maintenant ./DEF/subABC ).

Les autres versions de rename ont des syntaxes différentes – vérifiez vos pages de manuel.


Voici la version de rename basée sur Perl dérivée de la première édition de Perl ‘Camel Book’; la première version que j’ai sous contrôle de version a une date de 1992-01-05. Le changement effectué aujourd’hui a mis à jour la ligne shebang (utilise env, -w car il n’est pas fiable et ajoute use warnings; pour compenser l’absence de -w ). Les changements antérieurs ont été 2008, 1998, 1996 et 1992; cela n’a pas beaucoup changé au cours des 19 dernières années.

 #!/usr/bin/env perl # # @(#)$Id: rename.pl,v 1.8 2011/06/03 22:30:22 jleffler Exp $ # # Rename files using a Perl substitute or transliterate command use ssortingct; use warnings; use Getopt::Std; my(%opts); my($usage) = "Usage: $0 [-fnxV] perlexpr [filenames]\n"; my($force) = 0; my($noexc) = 0; my($trace) = 0; die $usage unless getopts('fnxV', \%opts); if ($opts{V}) { printf "%s\n", q'RENAME Version $Revision: 1.8 $ ($Date: 2011/06/03 22:30:22 $)'; exit 0; } $force = 1 if ($opts{f}); $noexc = 1 if ($opts{n}); $trace = 1 if ($opts{x}); my($op) = shift; die $usage unless defined $op; if (!@ARGV) { @ARGV = ; chop(@ARGV); } for (@ARGV) { if (-e $_ || -l $_) { my($was) = $_; eval $op; die $@ if $@; next if ($was eq $_); if ($force == 0 && -f $_) { print STDERR "rename failed: $was - $_ exists\n"; } else { print "+ $was --> $_\n" if $trace; print STDERR "rename failed: $was - $!\n" unless ($noexc || rename($was, $_)); } } else { print STDERR "$_ - $!\n"; } } 
 mkdir z; cd z; touch fooabcbar; touch fooABCbar find . -type 'f' \( -name '*ABC*' -o -name '*abc*' \) | while read f; do g=`echo "$f" | sed -e 's/abc/def/g' -e 's/ABC/DEF/g'`; echo mv -- "$f" "$g"; done 

Tant que le chemin d’access n’inclut pas de nouvelle ligne (très rare).

Si ce sont toujours les 3 derniers caractères, cela devrait fonctionner assez bien, je pense:

 mv *abc.* *def.*