Comment renommer tous les dossiers et fichiers en minuscules sous Linux?
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.
-
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.
-
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).
-
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é.
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:
-
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
etaBcDeF
? Le script de changement de nom doit-il abandonner ou simplement avertir et continuer? -
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?
-
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
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
Vous pouvez récupérer le fichier exemple Developers.mp3 à ici . , si nécessaire;)
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.