web-dev-qa-db-fra.com

Comment renommer tous les dossiers et fichiers en minuscules sous Linux?

Je dois renommer une arborescence de dossiers complète de manière récursive afin qu'aucune lettre majuscule n'apparaisse nulle part (c'est du code source C++, mais cela ne devrait pas avoir d'importance). Points bonus pour ignorer les fichiers/dossiers de contrôle CVS et SVN. La méthode préférée serait un script Shell, puisque Shell devrait être disponible sur n’importe quelle machine Linux.

Il y avait des arguments valables concernant les détails du renommage du fichier.

  1. Je pense que les fichiers avec les mêmes noms en minuscules devraient être écrasés, c'est le problème de l'utilisateur. En cas d'extraction sur un système de fichiers ignorant la casse, le premier sera écrasé par le dernier.

  2. Je considérerais les caractères A-Z et les transformerais en a-z, tout le reste n’appelant que des problèmes (au moins avec le code source).

  3. Le script serait nécessaire pour exécuter une compilation sur un système Linux. Je pense donc que les modifications apportées aux fichiers de contrôle CVS ou SVN devraient être omises. Après tout, il ne s'agit que d'une sortie à zéro. Peut-être qu'une "exportation" est plus appropriée.

151
vividos

Une version concise utilisant la commande "rename".

find my_root_dir -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;

Cela évite les problèmes de renommage des répertoires avant les fichiers et d'essayer de déplacer des fichiers dans des répertoires non existants (par exemple, "A/A" dans "a/a").

Ou, une version plus détaillée sans utiliser "rename".

for SRC in `find my_root_dir -depth`
do
    DST=`dirname "${SRC}"`/`basename "${SRC}" | tr '[A-Z]' '[a-z]'`
    if [ "${SRC}" != "${DST}" ]
    then
        [ ! -e "${DST}" ] && mv -T "${SRC}" "${DST}" || echo "${SRC} was not renamed"
    fi
done

P. S.

Ce dernier permet plus de flexibilité avec la commande de déplacement (par exemple, "svn mv").

158
Alex B

plus petit encore j'aime bien 

rename 'y/A-Z/a-z/' *

Sur les systèmes de fichiers insensibles à la casse tels que HFS + de OS X, vous voudrez ajouter l'indicateur -f 

rename -f 'y/A-Z/a-z/' *
232
tristanbailey
for f in `find`; do mv -v "$f" "`echo $f | tr '[A-Z]' '[a-z]'`"; done
79
Swaroop C H

Essayez simplement de suivre si vous n'avez pas à vous soucier de l'efficacité.

Zip -r foo.Zip foo/*
unzip -LL foo.Zip
62
Ginhing

La plupart des réponses ci-dessus sont dangereuses car elles ne traitent pas de noms contenant des caractères impairs. Votre pari le plus sûr pour ce genre de choses est d’utiliser l’option -print0 de find, qui mettra fin aux noms de fichiers contenant ascii NUL au lieu de\n. Ici, je soumets ce script, qui modifie uniquement les fichiers et non les noms de répertoires afin de ne pas confondre find. 

find .  -type f -print0 | xargs -0n 1 bash -c \
's=$(dirname "$0")/$(basename "$0"); 
d=$(dirname "$0")/$(basename "$0"|tr "[A-Z]" "[a-z]"); mv -f "$s" "$d"'

Je l'ai testé et cela fonctionne avec les noms de fichiers contenant des espaces, toutes sortes de citations, etc. Ceci est important car si vous exécutez, en tant que root, l'un de ces autres scripts sur une arborescence contenant le fichier créé par:

touch \;\ echo\ hacker::0:0:hacker:\$\'\057\'root:\$\'\057\'bin\$\'\057\'bash

... bien devinez quoi ...

14
niXar

Cela fonctionne si vous avez déjà ou configurez rename command (par exemple, via brew install in Mac):

rename --lower-case --force somedir/*
12
alemol

Homme, vous aimez trop compliquer les choses .. 

renommer 'y/A-Z/a-z /' *

9
Stephen

Cela fonctionne sur CentOS/Redhat ou d'autres distributions sans le script Perl rename:

for i in $( ls | grep [A-Z] ); do mv -i "$i" "`echo $i | tr 'A-Z' 'a-z'`"; done

Source: https://linuxconfig.org/rename-all-files-from-uppercase-to-lowercase-characters

(Dans certaines distributions, la commande par défaut rename provient de util-linux, et il s'agit d'un outil différent et incompatible.)

6
Pere

La question initiale demandait d'ignorer les répertoires SVN et CVS, ce qui peut être fait en ajoutant -Prune à la commande find. E.g pour ignorer CVS:

find . -name CVS -Prune -o -exec mv '{}' `echo {} | tr '[A-Z]' '[a-z]'` \; -print

[edit] J'ai essayé cela, et intégrer la traduction en minuscule à la découverte n'a pas fonctionné pour des raisons que je ne comprends pas vraiment. Alors, modifiez ceci pour:

$> cat > tolower
#!/bin/bash
mv $1 `echo $1 | tr '[:upper:]' '[:lower:]'`
^D
$> chmod u+x tolower 
$> find . -name CVS -Prune -o -exec tolower '{}'  \;

Ian

4
Ian Dickinson

Voici ma solution sous-optimale, utilisant un script bash shell:

#!/bin/bash
# first, rename all folders
for f in `find . -depth ! -name CVS -type d`; do
   g=`dirname "$f"`/`basename "$f" | tr '[A-Z]' '[a-z]'`
   if [ "xxx$f" != "xxx$g" ]; then
      echo "Renaming folder $f"
      mv -f "$f" "$g"
   fi
done

# now, rename all files
for f in `find . ! -type d`; do
   g=`dirname "$f"`/`basename "$f" | tr '[A-Z]' '[a-z]'`
   if [ "xxx$f" != "xxx$g" ]; then
      echo "Renaming file $f"
      mv -f "$f" "$g"
   fi
done

Edit: J'ai apporté quelques modifications sur la base des suggestions faites jusqu'à présent. Désormais, tous les dossiers sont renommés correctement, mv ne pose pas de questions lorsque les autorisations ne correspondent pas et les dossiers CVS ne sont pas renommés (les fichiers de contrôle CVS de ce dossier sont toujours renommés, malheureusement).

Edit: Puisque "find -depth" et "find | sort -r" renvoient la liste des dossiers dans un ordre utilisable pour le changement de nom, j'ai préféré utiliser "-depth" pour la recherche de dossiers.

4
vividos

Utiliser le fixateur de nom de fichier de Larry Wall

$op = shift or die $help;
chomp(@ARGV = <STDIN>) unless @ARGV;
for (@ARGV) {
    $was = $_;
    eval $op;
    die $@ if $@;
    rename($was,$_) unless $was eq $_;
}

c'est aussi simple que

find | fix 'tr/A-Z/a-z/'

(où fix est bien sûr le script ci-dessus)

4
agnul

Ceci est un petit script Shell qui répond à vos attentes:

root_directory="${1?-please specify parent directory}"
do_it () {
    awk '{ lc= tolower($0); if (lc != $0) print "mv \""  $0 "\" \"" lc "\"" }' | sh
}
# first the folders
find "$root_directory" -depth -type d | do_it
find "$root_directory" ! -type d | do_it

Notez l'action-profondeur dans la première recherche.

3
tzot

Le précédent message fonctionnera parfaitement sans modifications ou avec quelques ajustements pour des cas simples, mais vous voudrez peut-être prendre en compte certaines situations avant d'exécuter le changement de nom de lot:

  1. Que devrait-il se passer si vous avez deux noms ou plus au même niveau dans la hiérarchie des chemins qui ne diffèrent que par cas, comme ABCdef, abcDEF et aBcDeF? Le script de changement de nom doit-il abandonner ou simplement avertir et continuer?

  2. Comment définissez-vous les minuscules pour les noms non US-ASCII? Si de tels noms peuvent être présents, faut-il vérifier d'abord et exclure le passage?

  3. Si vous exécutez une opération de changement de nom sur des copies de travail CVS ou SVN, vous pouvez endommager la copie de travail si vous modifiez la casse des noms de fichier ou de répertoire. Le script doit-il également rechercher et ajuster les fichiers administratifs internes tels que .svn/entries ou CVS/Entries?

2
Mihai Limbășan

Avec MacOS,

Installez le paquetage rename,

brew install rename

Utilisation,

find . -iname "*.py" -type f | xargs -I% rename -c -f  "%"                       

Cette commande trouve tous les fichiers avec une extension *.py et convertit les noms de fichiers en minuscules.

`f` - forces a rename

Par exemple,

$ find . -iname "*.py" -type f
./sample/Sample_File.py
./sample_file.py
$ find . -iname "*.py" -type f | xargs -I% rename -c -f  "%"
$ find . -iname "*.py" -type f
./sample/sample_file.py
./sample_file.py
2
akilesh raj

Je voudrais atteindre pour python dans cette situation, pour éviter avec optimisme d'assumer des chemins sans espaces ni barres obliques. J'ai également constaté que python2 a tendance à être installé dans plus d'endroits que rename.

#!/usr/bin/env python2
import sys, os

def rename_dir(directory):
  print('DEBUG: rename('+directory+')')
  # rename current directory if needed
  os.rename(directory, directory.lower())
  directory = directory.lower()

  # rename children
  for fn in os.listdir(directory):
    path = os.path.join(directory, fn)
    os.rename(path, path.lower())
    path = path.lower()

    # rename children within, if this child is a directory
    if os.path.isdir(path):
        rename_dir(path)

# run program, using the first argument passed to this python script as the name of the folder
rename_dir(sys.argv[1])
1
John Foley

Dans OSX, mv -f affiche l'erreur "même fichier", aussi je renomme deux fois.

for i in `find . -name "*" -type f |grep -e "[A-Z]"`; do j=`echo $i | tr '[A-Z]' '[a-z]' | sed s/\-1$//`; mv $i $i-1; mv $i-1 $j; done
1
Jonghee Park

L’approche la plus simple que j’ai trouvée sur MacOSX consistait à utiliser le package de changement de nom de http://plasmasturm.org/code/rename/ :

brew install rename
rename --force --lower-case --nows *

--force Renommer même lorsqu'un fichier avec le nom de destination existe déjà.

--lower-case Convertit les noms de fichier en minuscules.

--nows Remplace toutes les séquences d'espaces dans le nom du fichier par des caractères de soulignement simples.

1
Kim T
for f in `find -depth`; do mv ${f} ${f,,} ; done

find -depth imprime chaque fichier et répertoire, avec le contenu d'un répertoire imprimé avant le répertoire lui-même. ${f,,} met en minuscule le nom du fichier.

1
Chris Schierkolk

Pas portable, seulement Zsh, mais assez concis.

Tout d’abord, assurez-vous que zmv est chargé.

autoload -U zmv

Assurez-vous également que extendedglob est activé:

setopt extendedglob

Alors utilisez:

zmv '(**/)(*)~CVS~**/CVS' '${1}${(L)2}'

Récursivement en minuscule les fichiers et les répertoires dont le nom n'est pasCVS.

1
benjwadams
find . -depth -name '*[A-Z]*'|sed -n 's/\(.*\/\)\(.*\)/mv -n -v -T \1\2 \1\L\2/p'|sh

Je n'ai pas essayé les scripts plus élaborés mentionnés ici, mais aucune des versions en ligne de commande simples ne fonctionnait pour moi sur mon NAS Synology. rename n'est pas disponible et de nombreuses variantes de find échouent, car il semble coller à l'ancien nom du chemin déjà renommé (par exemple, s'il trouve ./FOO suivi de ./FOO/BAR, renommer ./FOO en ./foo continuera de lister ./FOO/BAR même si ce chemin n'est plus valide). La commande ci-dessus a fonctionné pour moi sans aucun problème.

Ce qui suit est une explication de chaque partie de la commande:


find . -depth -name '*[A-Z]*'

Cela trouvera n'importe quel fichier du répertoire en cours (changez . en n'importe quel répertoire que vous voulez traiter), en utilisant une recherche en profondeur d'abord (par exemple, il listera ./foo/bar avant ./foo), mais uniquement pour les fichiers contenant une majuscule. Le filtre -name s'applique uniquement au nom du fichier de base, pas au chemin d'accès complet. Donc, ceci listera ./FOO/BAR mais pas ./FOO/bar. C'est bon, car nous ne voulons pas renommer ./FOO/bar. Nous voulons cependant renommer ./FOO, mais celui-ci est répertorié plus tard (c’est pourquoi -depth est important).

Cette commande en elle-même est particulièrement utile pour rechercher les fichiers que vous souhaitez renommer. Utilisez-le après la commande rename complete pour rechercher des fichiers qui n'ont toujours pas été remplacés en raison de collisions ou d'erreurs de noms de fichiers.


sed -n 's/\(.*\/\)\(.*\)/mv -n -v -T \1\2 \1\L\2/p'

Cette partie lit les fichiers générés par find et les formate dans une commande mv en utilisant une expression régulière. L'option -n empêche sed d'imprimer l'entrée et la commande p dans l'expression rationnelle de remplacement remplace le texte remplacé.

La regex elle-même consiste en deux captures: la partie jusqu'à la dernière/(qui est le répertoire du fichier) et le nom du fichier lui-même. Le répertoire est laissé intact, mais le nom du fichier est transformé en minuscule. Donc, si find génère ./FOO/BAR, il deviendra mv -n -v -T ./FOO/BAR ./FOO/bar. L'option -n de mv permet de s'assurer que les fichiers en minuscules existants ne sont pas écrasés. L'option -v permet à mv de générer chaque modification apportée (ou ne s'effectue pas - si ./FOO/bar existe déjà, il génère quelque chose comme ./FOO/BAR -> ./FOO/BAR, en notant qu'aucune modification n'a été apportée). Le -T est très important ici - il traite le fichier cible comme un répertoire. Cela garantira que ./FOO/BAR ne sera pas déplacé dans ./FOO/bar si ce répertoire existe.

Utilisez ceci avec find pour générer une liste de commandes qui seront exécutées (pratique pour vérifier ce qui sera fait sans le faire réellement)


sh

Cette jolie explicite. Il route toutes les commandes mv générées vers l'interpréteur Shell. Vous pouvez le remplacer par bash ou tout shell de votre choix.

0
oisyn
( find YOURDIR -type d | sort -r;
  find yourdir -type f ) |
grep -v /CVS | grep -v /SVN |
while read f; do mv -v $f `echo $f | tr '[A-Z]' '[a-z]'`; done

Commencez par renommer les répertoires de bas en haut sort -r (où -depth n'est pas disponible), puis les fichiers . Ensuite, grep -v/CVS au lieu de find ...- Prune parce que c'est plus simple . Pour les grands répertoires, for f in ... peut déborder de la mémoire tampon du shell . Utilisez find ... | en lisant pour éviter cela.

Et oui, cela encombrera des fichiers qui ne diffèrent que par le cas ...

0
pklausner

Si vous utilisez Arch Linux , vous pouvez installer rename package à partir de AUR qui fournit la commande renamexm en tant que /usr/bin/renamexm exécutable et son manual page.

C'est un outil vraiment puissant pour renommer rapidement des fichiers et des répertoires.

Convertir en minuscule

rename -l Developers.mp3 # or --lowcase

Convertir en majuscule

rename -u developers.mp3 # or --upcase, long option

Autres options

-R --recursive # directory and its children

-t --test # dry run, output but don't rename

-o --owner # change file owner as well to user specified

-v --verbose # output what file is renamed and its new name

-s/str/str2 # substite string on pattern

--yes # Confirm all actions

Vous pouvez récupérer le fichier exemple Developers.mp3 à partir de ici , si nécessaire;)

0
w17t

J'avais besoin de faire cela sur une configuration de cygwin sous Windows 7 et j'ai constaté que j'avais des erreurs de syntaxe avec les suggestions ci-dessus que j'avais essayées (bien que j'aie peut-être manqué une option de travail), mais cette solution directement depuis ubutu forums a fonctionné hors de la boîte :-)

ls | while read upName; do loName=`echo "${upName}" | tr '[:upper:]' '[:lower:]'`; mv "$upName" "$loName"; done

(nb j’avais précédemment remplacé les espaces par des traits de soulignement en utilisant

for f in *\ *; do mv "$f" "${f// /_}"; done
0
jacanterbury

Longy But "Fonctionne sans surprises ni installations"

Ce script traite les noms de fichiers avec des espaces, des guillemets, d’autres inhabituels caractères et Unicode, fonctionne sur les systèmes de fichiers non sensibles à la casse et la plupart des environnements Unix-y sur lesquels bash et awk sont installés (c'est-à-dire presque tous). Il signale également les collisions éventuelles (en laissant le nom du fichier en majuscule) et, bien sûr, renomme les fichiers et les répertoires et fonctionne de manière récursive. Enfin, il est très adaptable: vous pouvez modifier la commande find pour cibler les fichiers/répertoires de votre choix et Tweak awk pour effectuer d’autres manipulations de noms. Notez que par "gère Unicode", je veux dire qu'il convertira leur cas (ne les ignorez pas comme les réponses qui utilisent tr).

# adapt the following command _IF_ you want to deal with specific files/dirs
find . -depth -mindepth 1 -exec bash -c '
  for file do
    # adapt the awk command if you wish to rename to something other than lowercase
    newname=$(dirname "$file")/$(basename "$file" | awk "{print tolower(\$0)}")
    if [ "$file" != "$newname" ] ; then
        # the extra step with the temp filename is for case-insensitive filesystems
        if [ ! -e "$newname" ] && [ ! -e "$newname.lcrnm.tmp" ] ; then
           mv -T "$file" "$newname.lcrnm.tmp" && mv -T "$newname.lcrnm.tmp" "$newname" 
        else
           echo "ERROR: Name already exists: $newname"
        fi
    fi    
  done
' sh {} +

Références

Mon script est basé sur ces excellentes réponses:

https://unix.stackexchange.com/questions/9496/looping-through-files-with-spaces-in-the-names

Comment convertir une chaîne en minuscule dans Bash?

0
ndemou

Cela fonctionne bien aussi sur macOS:

Ruby -e "Dir['*'].each { |p| File.rename(p, p.downcase) }"
0
Chris

Slugify Rename (regex)

Ce n'est pas exactement ce que le PO a demandé, mais ce que j'espérais trouver sur cette page: 

Une version "slugify" pour renommer les fichiers afin qu'ils soient similaires aux URL
(c’est-à-dire inclure uniquement des caractères alphanumériques, des points et des tirets):

rename "s/[^a-zA-Z0-9\.]+/-/g" filename
0
cwd

Personne ne suggère de composition? 

typeset -l new        # always lowercase
find $topPoint |      # not using xargs to make this more readable
  while read old
  do mv "$old" "$new" # quotes for those annoying embedded spaces
  done

Sous Windows, les émulations telles que git bash peuvent échouer car Windows n'est pas sensible à la casse sous le capot. Pour ceux-là, ajoutez une étape qui mv le fichier est d'abord un autre nom, comme "$ old.tmp", puis à $ new. 

0
Paul Hodges