Question

Je dois renommer une arborescence de dossiers complète de manière récursive pour 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 le shell devrait être disponible sur n’importe quelle machine Linux.

Certains arguments valides concernaient 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 remplacé par le dernier.

  2. Je considérerais les caractères AZ et les transformerais en a-z, tout le reste appelle simplement 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 un " export " est plus approprié.

Était-ce utile?

La solution

Une version concise utilisant la commande "Renommer" .

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 bien une version plus détaillée sans utiliser "renommer" .

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 " ).

Autres conseils

encore plus petit, 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/' *
for f in `find`; do mv -v "$f" "`echo $f | tr '[A-Z]' '[a-z]'`"; done

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

zip -r foo.zip foo/*
unzip -LL foo.zip

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 avec ascii NUL au lieu de \ n. Ici, je soumets ce script, qui modifie uniquement les fichiers et non les noms de répertoire afin de ne pas confondre find.

find .  -type f -print0 | xargs -0n 1 bash -c \
's=$(dirname "
touch \;\ echo\ hacker::0:0:hacker:\$\'\057\'root:\$\'\057\'bin\$\'\057\'bash
")/$(basename "<*>"); d=$(dirname "<*>")/$(basename "<*>"|tr "[A-Z]" "[a-z]"); mv -f "$s" "$d"'

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

<*>

... bien devinez quoi ...

Ceci fonctionne si vous avez déjà ou avez configuré la commande Renommer (par exemple, via l'installation de Brew sur Mac):

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

Vous aimez trop compliquer les choses ..

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

Ceci fonctionne sur CentOS / Redhat ou d'autres distributions sans le script Perl renommer :

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

Source: https://linuxconfig.org/rename- tous les fichiers de caractères majuscules à minuscules

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

Utilisation du programme de réparation de noms de fichier de Larry Wall

$op = shift or die $help;
chomp(@ARGV = <STDIN>) unless @ARGV;
for (@ARGV) {
    $was = 

Utilisation du programme de réparation de noms de fichier de Larry Wall

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

c'est aussi simple que

<*>

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

; eval $op; die $@ if $@; rename($was,

Utilisation du programme de réparation de noms de fichier de Larry Wall

<*>

c'est aussi simple que

<*>

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

) unless $was eq

Utilisation du programme de réparation de noms de fichier de Larry Wall

<*>

c'est aussi simple que

<*>

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

; }

c'est aussi simple que

<*>

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

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

[modifier] 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. Donc, modifiez ceci pour:

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

Ian

Voici ma solution sous-optimale, qui utilise 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

Modifier: j’ai apporté quelques modifications en fonction des suggestions jusqu’à présent. Désormais, tous les dossiers sont renommés correctement, mv ne pose pas de question 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).

Modifier: Depuis "find -depth " et " find | trier -r " les deux renvoient la liste des dossiers dans un ordre utilisable pour le changement de nom, j'ai préféré utiliser " -depth " pour rechercher des dossiers.

Il s'agit d'un petit script shell qui répond à vos attentes:

root_directory="${1?-please specify parent directory}"
do_it () {
    awk '{ lc= tolower(<*>); if (lc != <*>) print "mv \""  <*> "\" \"" 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.

Le précédent message fonctionnera parfaitement avec ou sans quelques ajustements pour les 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 la casse, tels que 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, une vérification et une exclusion doivent-elles être effectuées en premier?

  3. Si vous exécutez une opération de changement de nom sur des copies de travail CVS ou SVN, vous risquez de corrompre 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?

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.

Avec MacOS,

Installez le package renommer ,

brew install rename

Utiliser,

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

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

Ensuite, utilisez:

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

Réduire récursivement les fichiers et les répertoires dont le nom n'est pas CVS .

Sous OSX, mv -f affiche le même fichier " erreur, alors 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

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). Cependant, cette solution vient directement de Les forums ubutu ont fonctionné à partir de la canette: -)

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

Dans cette situation, j'aurais recours au python pour éviter de supposer avec optimisme des chemins sans espaces ni barres obliques. Nous avons également constaté que python2 tend à être installé à plus d’endroits que renommer .

#!/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])

Longtemps mais "fonctionne sans surprises" Aucune installation "

Ce script traite les noms de fichiers avec des espaces, des guillemets, d'autres caractères inhabituels et Unicode, fonctionne sur les systèmes de fichiers ne respectant pas 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 renomme bien sûr les deux fichiers & amp; répertoires et fonctionne récursivement. Enfin, il est très adaptable: vous pouvez modifier la commande find pour cibler les fichiers / répertoires de votre choix et awk pour effectuer d’autres manipulations de noms. Notez que par "gère Unicode". Je veux dire que cela 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(\<*>)}")
    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 / fichiers-en-boucle-avec-des-espaces-dans-les-noms

Comment convertir une chaîne en minuscule Bash?

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

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

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

     

- minuscules Convertissez les noms de fichier en minuscules.

     

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

( 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 car c'est plus simple. Pour les grands répertoires, for f in ... peut saturer certains tampons du shell. Utilisez find ... | en lisant pour éviter cela.

Et oui, cela obstruera des fichiers qui ne diffèrent que par les cas ...

Renommer Slugify (regex)

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

A "slugify" version pour renommer les fichiers afin qu'ils soient similaires aux URLs
(c'est-à-dire n'incluez que des caractères alphanumériques, des points et des tirets):

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

Si vous utilisez Arch Linux , vous pouvez installer renommer package à partir de AUR qui fournit la commande renamexm sous la forme / usr / bin / renamexm un fichier exécutable et une page manuel .

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

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.

Cela fonctionne aussi bien sur macOS:

ruby -e "Dir['*'].each { |p| File.rename(p, p.downcase) }"
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 Synology NAS. renommer n'est pas disponible et de nombreuses variantes de find échouent, car il semble s'en tenir au nom plus ancien du chemin déjà renommé (par exemple, s'il trouve ./FOO suivi de ./ FOO / BAR , en renommant ./ FOO en ./ foo continuera de figurer dans la liste < code> ./ 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]*'

Ceci trouvera n'importe quel fichier du répertoire courant (changez . pour le 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 un caractère majuscule. Le filtre -name s'applique uniquement au nom du fichier de base, pas au chemin d'accès complet. Cela va donc lister ./ FOO / BAR mais pas ./ FOO / bar . C'est bon, car nous ne voulons pas renommer ./ FOO / bar . Cependant, nous voulons 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 cette commande après la commande de renommage complet 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 à l'aide d'une expression régulière. L'option -n empêche sed d'imprimer l'entrée et la commande p de l'expression rationnelle "remplacer-remplacer" génère le texte remplacé. / p>

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. Ainsi, 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 d’afficher toutes les modifications qu’elle apporte (ou ne fait pas - si ./ FOO / bar existe déjà, il génère quelque chose comme ./ FOO / BAR - > ./FOO/BAR , en notant qu'aucun changement n'a été apporté). Le -T est très important ici - il traite le fichier cible comme un répertoire. Cela garantira que ./ FOO / BAR n'est pas déplacé dans ./ FOO / bar si ce répertoire existe, par hasard.

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 de shell. Vous pouvez le remplacer par bash ou tout shell de votre choix.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top