Comment renommer tous les dossiers et fichiers en minuscules sous Linux?
je dois renommer un arbre de dossiers complet de façon récursive afin qu'aucune lettre en majuscule n'apparaisse nulle part (c'est le code source C++, mais cela ne devrait pas avoir d'importance). Points Bonus pour ignorer CVS et les fichiers/dossiers de contrôle 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 quelques arguments valables sur les détails du renommage du fichier.
-
je pense que les fichiers avec la même minuscule les noms doivent être réécrits, c'est le problème de l'utilisateur. Une fois vérifié sur un système de fichier ignorant cas serait écraser le premier avec le dernier, aussi.
-
je considérerais les caractères A-Z et les transformerais en A-z, tout le reste appelle juste pour des problèmes (au moins avec le code source).
-
le script serait nécessaire pour exécuter une construction sur un système Linux, donc je pense que des changements aux fichiers de contrôle CVS ou SVN doit être omis. Après tout, c'est juste une égratignure de la caisse. Peut-être une "exportation" est plus approprié.
24 réponses
une version concise utilisant la commande "rename"
.
find my_root_dir -depth -exec rename 's/(.*)\/([^\/]*)/\/\L/' {} \;
cela évite les problèmes avec les répertoires étant renommés avant les fichiers et essayant de déplacer des fichiers dans les répertoires non existants (par exemple "A/A"
dans "a/a"
).
Ou, une version plus détaillée, sans l'aide de "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 une plus grande flexibilité avec la commande move (E. G. "svn mv"
).
encore plus petit j'aime bien
rename 'y/A-Z/a-z/' *
sur les systèmes de fichiers insensibles à la casse tels que HFS+ D'OS X, vous voudrez ajouter le drapeau-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 besoin de se soucier de l'efficacité.
zip -r foo.zip foo/*
unzip -LL foo.zip
la plupart des réponses ci-dessus sont dangereuses parce qu'elles ne traitent pas de noms contenant des caractères impairs. Votre pari le plus sûr pour ce genre de chose est d'utiliser l'option find's-print0, qui terminera les noms de fichiers avec ascii NUL au lieu de \N. Ici, je soumets ce script, qui ne modifie que les fichiers et pas les noms de répertoire pour ne pas confondre find.
find . -type f -print0 | xargs -0n 1 bash -c \
's=$(dirname ""151900920"")/$(basename ""151900920"");
d=$(dirname ""151900920"")/$(basename ""151900920""|tr "[A-Z]" "[a-z]"); mv -f "$s" "$d"'
je l'ai testé et il fonctionne avec des noms de fichiers contenant des espaces, toutes sortes de citations, etc. C'est important parce que si vous exécutez, comme root, un de ces Autres scripts sur un arbre qui inclut le fichier créé par:
touch \;\ echo\ hacker::0:0:hacker:$\'7\'root:$\'7\'bin$\'7\'bash
... eh bien, devinez quoi ...
cela fonctionne si vous avez déjà ou mis en place la commande renommer (par exemple via brew install En Mac):
rename --lower-case --force somedir/*
vous aimez compliquer les choses..
renommer 'y / A-Z / A-z/' *
à l'Aide de Larry Wall nom du fichier fixateur
$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)
la question initiale demandait d'ignorer les répertoires SVN et CVS, ce qui peut être fait en ajoutant-prune à la commande find. Par exemple, pour ignorer CVS:
find . -name CVS -prune -o -exec mv '{}' `echo {} | tr '[A-Z]' '[a-z]'` \; -print
[edit] j'ai essayé cela, et l'intégration de la traduction minuscule à l'intérieur de la trouvaille n'a pas fonctionné pour des raisons que je ne comprends pas vraiment. Modifier comme suit:
$> cat > tolower
#!/bin/bash
mv `echo | tr '[:upper:]' '[:lower:]'`
^D
$> chmod u+x tolower
$> find . -name CVS -prune -o -exec tolower '{}' \;
Ian
voici ma solution sous-optimale, en utilisant un script Shell bash:
#!/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 fait quelques modifications basées sur les suggestions jusqu'à présent. Maintenant les dossiers sont tous renommés correctement, mv ne pose pas de questions quand les permissions ne correspondent pas, et les dossiers CVS ne sont pas renommés (les fichiers de contrôle CVS à l'intérieur de ce dossier sont encore renommés, malheureusement).
Edit: depuis "find-depth" et "find | sort-r" Tous les deux renvoient la liste des dossiers dans un ordre utilisable pour renommer, j'ai préféré utiliser "- depth " pour la recherche de dossiers.
c'est un petit script shell qui fait ce que vous avez demandé:
root_directory="${1?-please specify parent directory}"
do_it () {
awk '{ lc= tolower("151900920"); if (lc != "151900920") print "mv \"" "151900920" "\" \"" lc "\"" }' | sh
}
# first the folders
find "$root_directory" -depth -type d | do_it
find "$root_directory" ! -type d | do_it
Note la profondeur d'action à la première de trouver.
cela fonctionne sur les distributions CentOS / Redhat ou autres 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 certains cas, la commande par défaut rename
vient d'util-linux, et c'est un outil différent et incompatible)
le précédemment affiché fonctionnera parfaitement hors de la boîte ou avec quelques ajustements pour les cas simples, mais il ya des situations que vous pourriez vouloir prendre en compte avant d'exécuter le lot renommer:
-
que se passe-t-il si vous avez deux ou plusieurs noms au même niveau dans la hiérarchie des chemins qui ne diffèrent que par cas, tels que
ABCdef
,abcDEF
etaBcDeF
? Le script renommé devrait-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, devrait-on effectuer une vérification et exclure la réussite en premier?
-
si vous effectuez une opération de renommage sur des copies de travail CVS ou SVN, vous risquez de corrompre la copie de travail si vous changez le cas sur les noms de fichiers ou de répertoires. Si le script trouve et ajuste aussi des dossiers administratifs internes tels que .svn / entrées ou CVS / entrées?
Avec MacOS,
Installer rename
package
brew install rename
Use,
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, Zsh seulement, mais assez concis.
D'abord, assurez-vous que zmv
est chargé.
autoload -U zmv
aussi, assurez-vous que extendedglob
est sur:
setopt extendedglob
puis utiliser:
zmv '(**/)(*)~CVS~**/CVS' '${(L)2}'
pour les fichiers et répertoires en minuscules lorsque le nom n'est pas CVS .
dans OSX, mv-f affiche une erreur" même fichier", donc j'ai renommé 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
je voudrais atteindre python dans cette situation, pour éviter d'assumer de façon optimiste des chemins sans espaces ou des entailles. J'ai également constaté que python2
tend à ê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])
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,,}
réduit le nom du fichier.
( 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
renommer D'abord les répertoires bas vers le haut trier-R (où-la profondeur n'est pas disponible), puis les fichiers. Puis grep-v /CVS au lieu de find ...- prune parce que c'est plus simple. Pour les grands répertoires, pour F in ... peut déborder certains tampons shell. Utilisez find ... / tout en lisant pour éviter cela.
et oui, cela clouera les fichiers qui diffèrent seulement dans le cas...
Slugify Renommer (regex)
pas exactement ce que l'OP demandait, 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 uniquement inclure alphanumériques, de points et de tirets):
rename "s/[^a-zA-Z0-9\.]+/-/g" filename
j'avais besoin de faire cela sur une configuration de cygwin sur Windows 7 et j'ai constaté que j'ai eu des erreurs de syntaxe avec les suggestions ci-dessus que j'ai essayé (bien que j'ai peut-être manqué une option de travail) cependant cette solution directement de forums ubutu travaillé à partir de la can: -)
ls | while read upName; do loName=`echo "${upName}" | tr '[:upper:]' '[:lower:]'`; mv "$upName" "$loName"; done
( nb: j'avais déjà remplacer les espaces par des caractères de soulignement à l'aide de
for f in *\ *; do mv "$f" "${f// /_}"; done
si vous utilisez Arch Linux , vous pouvez installer rename
paquet de AUR
qui fournit renamexm
commande comme /usr/bin/renamexm
exécutable et un son manuel page avec elle.
c'est un outil vraiment puissant pour renommer rapidement des fichiers et des répertoires.
convertir en minuscules
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 permet de récupérer l'échantillon des Développeurs.mp3 fichier de 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
sur les émulations de fenêtres comme git bash cela peut échouer parce que les fenêtres ne sont pas sensibles à la casse sous le capot. Pour ceux-là, ajouter une étape que mv est le fichier à un autre nom d'abord, comme "$old.tmp", puis à $nouveau.
Longue Mais "Fonctionne Avec Pas De Surprises, Pas De Des Installations"
ce script gère les noms de fichiers avec des espaces, des guillemets, d'autres caractères inhabituels et Unicode, fonctionne sur des systèmes de fichiers insensibles à la casse et la plupart des environnements Unix-y qui ont bash et awk 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 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/dirs que vous souhaitez et vous pouvez modifier awk pour faire d'autres manipulations de noms. Notez que par " handles Unicode "je veux dire qu'il va effectivement convertir leur cas (ne pas les ignorer 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