Quiero poner en minúscula el nombre de cada directorio debajo de un directorio. ¿Con qué comandos puedo hacer eso?
fuente
Quiero poner en minúscula el nombre de cada directorio debajo de un directorio. ¿Con qué comandos puedo hacer eso?
¿Todos los directorios en un nivel, o recursivamente?
En un nivel:
autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'
Recursivamente:
zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'
Explicaciones: zmv
cambia el nombre de los archivos que coinciden con un patrón de acuerdo con el texto de reemplazo dado. -o-i
pasa la -i
opción a cada mv
comando 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 $2
a minúsculas.
En un nivel:
for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done
El final /
restringe la correspondencia con los directorios y mv -i
hace que solicite confirmación en caso de una colisión. Elimine -i
para sobrescribir en caso de una colisión, y use yes n | for …
. para que no se le solicite y no realice ningún cambio de nombre que colisionaría.
Recursivamente:
find root/* -depth -type d -exec sh -c '
t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;
El uso de -depth
asegura que los directorios profundamente anidados se procesen antes que sus antepasados. El procesamiento del nombre depende de que haya un /
; si desea llamar a operar en el directorio actual, use ./*
(adaptar el script de shell para hacer frente .
o *
se deja como un ejercicio para el lector).
Aquí utilizo el script de cambio de nombre de Perl que Debian y Ubuntu incluyen /usr/bin/prename
(normalmente también disponible rename
). En un nivel:
rename 's!/([^/]*/?)$!\L/$1!' root/*/
Recursivamente, con bash ≥4 o zsh:
shopt -s globstar # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/
Recursivamente, portablemente:
find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +
mv -i a a
dé "mv: cambie el nombre de a a / a: argumento no válido".-execdir
que es increíble: unix.stackexchange.com/questions/5412/… Luego descubrí que tiene algo dePATH
locura y estaba triste :-(No hay un solo comando que haga eso, pero puedes hacer algo como esto:
Si necesita que sea robusto, debe tener en cuenta cuando ya hay dos directorios que difieren solo en el caso.
Como una línea:
fuente
for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
find -type d
, pero no pude entenderlofor fd in */;
, evitando así la necesidad de verificar si era un directorio, pero no tengo idea si este instinto fue bueno.tr
ya espera un intervalo, por lotr '[A-Z]' '[a-z]'
traduce[
a[
y]
a]
de paso. Esto es inútil pero inofensivo; sin embargo, sin las comillas, el shell expandiría los corchetes si hubiera un archivo con un nombre de una letra mayúscula en el directorio actual.Tomé esto como un desafío de una línea :) Primero, establezca un caso de prueba:
Yo uso
find
para detectar los directorios con letras mayúsculas y luego en minúsculas a través de . Supongo que usar es un poco hack-ish, pero mi cabeza siempre explota cuando trato de escapar de las cosas directamente.sh -c 'mv {}
echo {} | tr [:upper:] [:lower:]
'sh -c
find
Tenga cuidado: ¡esta solución no comprueba si la reducción de la capa conduce a colisiones!
fuente
mv -i
. Un problema mayor es que no ha utilizado las comillas adecuadas, por lo que su comando fallará si hay caracteres especiales (espacios en blanco o\[*?
) en cualquier parte del nombre. No tiene sentido usarlo afind
menos que recurra, y luego necesitafind -depth
y-path
debe ser-name
. Vea mi respuesta para ejemplos de trabajo.mv -i
después de escribir esto. Buen punto con la cita ...find -execdir
El | rebautizarEsta sería la mejor manera de hacerlo si no fuera por la locura de la ruta relativa, ya que evita que Perl regex fu solo actúe en el nombre base:
-execdir
primerocd
s en el directorio antes de ejecutar solo en el nombre base.Desafortunadamente, no puedo deshacerme de esa
PATH
parte de piratería, sefind -execdir
niega a hacer nada si tiene una ruta relativa enPATH
...: /ubuntu/621132/why-using-the-execdir-action- is-insecure-for-directory-which-is-in-the-path / 1109378 # 1109378fuente