cambiar todo el árbol de directorios a nombres en minúsculas

12

Estoy trabajando en una conversión de sitio web. Los archivos, ya que estaban vinculados y servidos desde el servidor web, no distinguen entre mayúsculas y minúsculas. Pero hice un volcado del sitio en mi sistema Linux y estoy escribiendo scripts para migrar datos. El problema es que me encuentro con problemas de mayúsculas y minúsculas entre las cadenas de enlaces en las páginas y el caso real de palabras en el sistema de archivos.

Por ejemplo, una página puede tener un enlace como <a href='/subfolder/PageName.asp'>mientras el archivo real es /subfolder/pagename.asp. Del mismo modo con las imágenes, <img src='spacer_sm.gif'>podría ser Spacer_Sm.gif.

Entonces, mi idea es cambiar todos los directorios y nombres de archivos a sus equivalentes en minúsculas para la descarga del sitio. ¿Cómo hago esto (y podría haber una mejor manera?)

Incluso si hay comandos unix que tienen conmutadores que no distinguen entre mayúsculas y minúsculas, estoy usando php, por lo que no todos los comandos del sistema de archivos tienen opciones para la distinción entre mayúsculas y minúsculas.

usuario394
fuente
2
Ver una pregunta anterior similar . He publicado una respuesta más simple aquí porque la pregunta es un poco más específica.
Gilles 'SO- deja de ser malvado'

Respuestas:

8

No sé si tu sabor unix tiene un rename. Muchas Linux tienen, y es parte de un paquete perl, si busca un repositorio.

find ./ -depth -exec rename -n 'y/[A-Z]/[a-z]/' {} ";"

Versión anterior con

rename -n 

en realidad no realiza la acción, sino que solo imprime lo que se haría. Omite el -n para hacerlo de verdad.

usuario desconocido
fuente
¿Qué 'lenguaje' o expresión regular es la 'y/[A-Z]/[a-z]/'parte?
user394
Bueno, como renamees parte de un perlpaquete, supongo que perl, pero el patrón también se usa sed, y tal vez AWKtambién. Solo sé sedcallar bien. Traduzco ya translateo map, pero no sé dónde están los orígenes del personaje.
usuario desconocido el
Debe ser perl regex: Gilles en su respuesta dice que renamees un guión perl.
user394
Sí, y puede usar expresiones regulares perl para modificar los nombres de archivo, lo que no necesariamente concluye de estar escrito en perl, pero que podría ser la pregunta más interesante.
Usuario desconocido
9

Zsh

zmv -o-i '(**/)(*)' '$1${2:l}'

Explicaciones: zmvcambia el nombre de los archivos que coinciden con un patrón de acuerdo con el texto de reemplazo dado. -o-ipasa la -iopción a cada mvcomando debajo del capó (ver más abajo). En el texto de reemplazo, $1, $2, etc, son los grupos sucesivos entre paréntesis en el patrón. **significa todos los directorios (sub) *, recursivamente. El final (/)no es un grupo entre paréntesis, sino un calificador global que significa que solo coinciden con los directorios. ${2:l}Convierte $2a minúsculas.

Perl renombrar

Aquí uso el script de cambio de nombre de Perl que Debian y Ubuntu incluyen /usr/bin/prename(también disponible normalmente rename). Con bash ≥4 o zsh:

shopt -s globstar  # only in bash
rename 's!/([^/]*/?)$!\L/$1!' **/*

Con otras conchas:

find . -depth -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +

Portátil

Recursivamente:

find . -depth -exec sh -c '
    t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
    [ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;

El uso de -depthasegura que los directorios profundamente anidados se procesen antes que sus antepasados.

Gilles 'SO- deja de ser malvado'
fuente
1

No funcionó en la siguiente estructura de directorios:

JKL/
deF/
ABC/DEf
ABC/gHi
ghi/jkL

Aquí hay un ejemplo que funciona:

for i in `find | sort -r | sed '$d'`; do \
   b=${i%/*}; e=${i##*/}; mv $i $b'/'${e,,}; done

Para una explicación sobre by evars:

man bash

Luego use la siguiente secuencia de teclas: /,,Enterbb

Baroneso
fuente
0

La respuesta aceptada no funcionó para mí, ya que trató de cambiar todos los directorios a la vez. Encontré otra solución en stackexchange muy similar a la portátil de Gilles arriba: de Baramin -
/programming/4268591/unix-rename-files-directories-to-uppercase

Lo he copiado aquí:

find . -depth | \
while read LONG; do
   SHORT=$( basename "$LONG" | tr '[:lower:]' '[:upper:]' )
   DIR=$( dirname "$LONG" )
   if [ "${LONG}" != "${DIR}/${SHORT}"  ]; then
     mv "${LONG}" "${DIR}/${SHORT}"
   fi
done

A lo que cambié el comando tr a ie: sed s / cat / dog / g

Cualquier agradecimiento va a Baramin en el enlace de arriba.

JJones
fuente