¿Cómo cambiar el nombre de todas las carpetas y archivos a minúsculas en Linux?

Tengo que cambiar el nombre de un árbol de carpetas completo recursivamente para que no aparezca ninguna letra mayúscula en ningún lugar (es código fuente C ++, pero eso no debería importar). Puntos de bonificación por ignorar archivos / carpetas de control CVS y SVN. La forma preferida sería un script de shell, ya que el shell debería estar disponible en cualquier caja de Linux.

Hubo algunos argumentos válidos sobre los detalles del cambio de nombre del archivo.

  1. Creo que los archivos con los mismos nombres en minúscula deben sobrescribirse, es el problema del usuario. Cuando se desprotege en un sistema de archivo ignorante de mayúsculas y minúsculas también sobrescribiría el primero con este último.

  2. Consideraría los caracteres AZ y los transformaría en az, todo lo demás es solo un problema (al menos con el código fuente).

  3. El script sería necesario para ejecutar una comstackción en un sistema Linux, por lo que creo que los cambios a los archivos de control CVS o SVN deberían omitirse. Después de todo, es solo un proceso de cero. Tal vez una “exportación” sea más apropiada.

Una versión concisa usando el comando "rename" .

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

Esto evita problemas con los directorios que se renombran antes de los archivos y tratando de mover los archivos a directorios no existentes (por ejemplo, "A/A" en "a/a" ).

O una versión más detallada sin usar "rename" .

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

PD

Este último permite una mayor flexibilidad con el comando de movimiento (por ejemplo, "svn mv" ).

más pequeño todavía me gusta bastante

 rename 'y/AZ/az/' * 

En sistemas de archivos insensibles a las mayúsculas y minúsculas, como HFS + de OS X, querrá agregar el indicador -f

 rename -f 'y/AZ/az/' * 
 for f in `find`; do mv -v "$f" "`echo $f | tr '[AZ]' '[az]'`"; done 

Simplemente intente seguir si no necesita preocuparse por la eficiencia.

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

La mayoría de las respuestas anteriores son peligrosas porque no tratan con nombres que contienen caracteres impares. Su apuesta más segura para este tipo de cosas es usar la opción -print0 de find, que terminará los nombres de archivo con ascii NUL en lugar de \ n. Aquí presento este script, que solo altera los archivos y no los nombres de los directorios para no confundir el find.

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

Lo probé y funciona con nombres de archivos que contienen espacios, todo tipo de citas, etc. Esto es importante porque si ejecuta, como raíz, uno de esos otros guiones en un árbol que incluye el archivo creado por:

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

… bien adivina que …

Esto funciona si ya tiene o ha configurado el comando de cambio de nombre (por ejemplo, a través de brew install en Mac):

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

Hombre a ustedes les gusta complicar las cosas …

renombrar ‘y / AZ / az /’ *

Usando el fijador de nombres de archivo de Larry Wall

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

es tan simple como

 find | fix 'tr/AZ/az/' 

(donde la solución es, por supuesto, el script anterior)

La pregunta original pedía ignorar los directorios SVN y CVS, lo cual se puede hacer agregando -prune al comando find. Por ejemplo, ignorar CVS:

 find . -name CVS -prune -o -exec mv '{}' `echo {} | tr '[AZ]' '[az]'` \; -print 

[edit] Probé esto, e insertar la traducción en minúsculas dentro del hallazgo no funcionó por razones que en realidad no entiendo. Por lo tanto, enmendar esto a:

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

Ian

Aquí está mi solución subóptima, usando un script de Bash Shell:

 #!/bin/bash # first, rename all folders for f in `find . -depth ! -name CVS -type d`; do g=`dirname "$f"`/`basename "$f" | tr '[AZ]' '[az]'` 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 '[AZ]' '[az]'` if [ "xxx$f" != "xxx$g" ]; then echo "Renaming file $f" mv -f "$f" "$g" fi done 

Editar: hice algunas modificaciones basadas en las sugerencias hasta el momento. Ahora todas las carpetas se renombraron correctamente, mv no hace preguntas cuando los permisos no coinciden, y las carpetas de CVS no se renombran (desafortunadamente, los archivos de control de CVS dentro de esa carpeta todavía se renombran).

Editar: Dado que “find -depth” y “find | sort -r” devuelven la lista de carpetas en un orden utilizable para el cambio de nombre, prefiero usar “-depth” para buscar carpetas.

Este es un pequeño script de shell que hace lo que solicitó:

 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 

Tenga en cuenta la acción de profundidad en el primer hallazgo.

Esto funciona en CentOS / Redhat u otras distribuciones sin rename el rename secuencia de comandos Perl:

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

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

(En algunas distribuciones, el comando de rename predeterminado proviene de util-linux, y esa es una herramienta diferente e incompatible)

Lo publicado anteriormente funcionará perfectamente o con algunos ajustes para casos simples, pero hay algunas situaciones que quizás desee tener en cuenta antes de ejecutar el cambio de nombre del lote:

  1. ¿Qué debería suceder si tiene dos o más nombres en el mismo nivel en la jerarquía de ruta que difieren solo por caso, como ABCdef , abcDEF y aBcDeF ? ¿El script de cambio de nombre debe abortarse o simplemente advertir y continuar?

  2. ¿Cómo se definen minúsculas para nombres que no sean US-ASCII? Si dichos nombres pueden estar presentes, ¿se debe realizar primero un pase de verificación y exclusión?

  3. Si está ejecutando una operación de cambio de nombre en copias de trabajo de CVS o SVN, puede dañar la copia de trabajo si cambia el caso en los nombres de archivos o directorios. ¿El script también debería encontrar y ajustar archivos administrativos internos como .svn / entries o CVS / Entries?

Con MacOS,

Instale el paquete de rename ,

 brew install rename 

Utilizar,

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

Este comando busca todos los archivos con una extensión *.py y convierte los nombres de los archivos a minúsculas.

 `f` - forces a rename 

Muestra de salida,

 $ 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 

No es portátil, solo Zsh, pero bastante conciso.

Primero, asegúrese de que zmv esté cargado.

 autoload -U zmv 

Además, asegúrese de que extendedglob esté activado:

 setopt extendedglob 

Luego usa:

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

Para archivos y directorios en minúscula recursiva donde el nombre no es CVS .

En OSX, mv -f muestra el error “mismo archivo”, por lo que renombro dos veces.

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

Me gustaría llegar a Python en esta situación, para evitar asumir de manera optimista caminos sin espacios ni barras. También descubrí que python2 tiende a instalarse en más lugares 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 cada archivo y directorio, con el contenido de un directorio impreso antes del directorio. ${f,,} minúsculas del nombre del archivo.

 ( 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 '[AZ]' '[az]'`; done 

Primero cambie el nombre de los directorios de abajo hacia arriba -r (donde -depth no está disponible), luego los archivos. Luego grep -v / CVS en lugar de encontrar …- podar porque es más simple. Para directorios grandes, for f in … puede desbordar algunos búferes de shell. Use encontrar … | mientras lees para evitar eso.

Y sí, esto borrará archivos que difieren solo en el caso …

Slugify Rename (regex)

No es exactamente lo que pidió el OP, pero lo que esperaba encontrar en esta página:

Una versión de “slugify” para cambiar el nombre de los archivos para que sean similares a las URL
(es decir, solo incluya caracteres alfanuméricos, puntos y guiones):

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

Necesitaba hacer esto en una configuración cygwin en Windows 7 y encontré que obtuve errores de syntax con las sugerencias anteriores que probé (aunque puede haber perdido una opción de trabajo) sin embargo, esta solución de foros directamente desde ubutu funcionó fuera de la lata 🙂

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

(nb Anteriormente había reemplazado el espacio en blanco con guiones bajos usando

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

Si usa Arch Linux , puede instalar el paquete de rename de AUR que proporciona el comando renamexm como /usr/bin/renamexm ejecutable y una página de manual junto con él.

Es una herramienta realmente poderosa para cambiar rápidamente el nombre de archivos y directorios.

Convertir a minúsculas

 rename -l Developers.mp3 # or --lowcase 

Convertir a mayúscula

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

Otras opciones

 -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 

Puede buscar el archivo de ejemplo Developers.mp3 desde aquí , si es necesario;)

¿Nadie sugiere tipografía?

 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 

En las emulaciones de Windows como git bash, esto puede fallar porque las ventanas no distinguen entre mayúsculas y minúsculas. Para ellos, agregue primero un paso que mv sea el archivo a otro nombre, como “$ old.tmp”, luego a $ new.