2011-01-17 24 views
5

i significa deshacerse de caracteres especiales en los nombres de archivo, etc.recursiva "normalizar" los nombres de archivo

he hecho un script, que recurrentemente se puede cambiar el nombre de archivos [http://pastebin.com/raw.php?i= kXeHbDQw]:

por ejemplo: antes:

THIS i.s my file (1).txt 

después de ejecutar la secuencia de comandos:

This-i-s-my-file-1.txt 

Ok. aquí está:

Pero: cuando quería probarlo "totalmente", con nombres de archivo como este:

¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÂÃÄÅÆÇÈÊËÌÎÏÐÑÒÔÕ×ØÙUÛUÝÞßàâãäåæçèêëìîïðñòôõ÷øùûýþÿ.txt 
áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&'()*+,:;<=>[email protected][\]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£.txt 

falla [http://pastebin.com/raw.php?i=iu8Pwrnr ]:

$ sh renamer.sh directorythathasthefiles 
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>[email protected][]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory 
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>[email protected][]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory 
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>[email protected][]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory 
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>[email protected][]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory 
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>[email protected][]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory 
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>[email protected][]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£': No such file or directory 
mv: cannot stat `./áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>[email protected][]^_`{|}~€‚ƒ„…†....and so on 
$ 

por lo que "mv" no puede manejar caracteres especiales ..: \

he trabajado en él durante muchas horas ..

¿Alguien tiene uno que funcione? [¿que puede manejar caracteres [nombres de archivos] en esas 2 líneas también?]

+5

[Tasa de respuesta aceptada de cero] (http://superuser.com/faq#howtoask) no hace su perfil verse bien. – grawity

+4

No lo haga [cross-post] (http://serverfault.com/questions/223514/recursively-normalize-filenames). –

+2

¿Por qué se migró del superusuario? Esto es un script de shell, no de programación ... – leppie

Respuesta

4

Suponiendo que el resto de su secuencia de comandos es correcta, su problema es que está usando read pero debe usar read -r. Observe cómo la barra invertida desapareció:

áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&'()*+,:;<=>[email protected][\]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£.txt 
áíüűúöőóéÁÍÜŰÚÖŐÓÉ!"#$%&\'()*+,:;<=>[email protected][]^_`{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£ 
17

mv maneja caracteres especiales bien. Tu script no.


En ningún orden en particular:

  1. está usando el find para encontrar todos los directorios, y ls cada directorio separado.

    1. ¿Por qué utilizar for DEPTH in... si se puede hacer exactamente lo mismo con uno de comandos?

      find -maxdepth 100 -type d 
      
    2. que hace que el límite de profundidad arbitraria innecesaria

      find -type d 
      
    3. ¿No vez analizar la salida de ls, especialmente si se puede dejar que find mango que también

      find -not -type d 
      
    4. asegurarse de que funciona en el peor de los casos posibles:

      find -not -type d -print0 | while read -r -d '' FILENAME; do 
      

      Esto detiene read de comer ciertos escapes y asfixia con nombres de archivo con caracteres de nueva línea.

  2. Usted está repitiendo todo el ciclo ls | replace para cada personaje. No - mata el rendimiento. Bucle más de cada directorio todos los archivos una vez, y simplemente utilice múltiples sed, o múltiples reemplazos en un comando sed.

    sed 's/á/a/g; s/í/i/g; ...' 
    

    (Iba a sugerir sed 'y/áí/ai/', pero lamentablemente eso no parece trabajar con Unicode Tal vez lo haría. perl -CS -Mutf8 -pe 'y/áí/ai/'.)

  3. todavía estás pensando en ASCII: "otros caracteres especiales - Códigos ASCII 33 .. ..255 ". No lo hagas

    1. En estos días, la mayoría de los sistemas utilizan Unicode en la codificación UTF-8, que tiene una gran gama más amplia de caracteres "especiales" - tan grande que enumerarlos uno a uno se vuelve inútil. (Es incluso multibyte - "e" es un byte, "ė" es de tres bytes.)

    2. True ASCII tiene 128 caracteres. Lo que tienes actualmente en mente son los juegos de caracteres ISO 8859 (a veces llamados "ANSI"), en particular, ISO 8859-1. Pero suben hasta 8859-16, y solo la parte "ASCII" permanece igual.

  4. echo -n $(command) es bastante inútil.

  5. Hay formas mucho más sencillas de encontrar el directorio y el nombre dado a una ruta. Por ejemplo, se puede hacer

    directory=$(dirname "$path") 
    oldnname=$(basename "$path") 
    # filter $oldname 
    mv "$path" "$directory/$newname" 
    
  6. Haz no uso egrep para comprobar si hay errores. Verifique el código de retorno del programa. (Como ya haces con cd.)

  7. Y en lugar de filtrar otros errores, haz ...

    if [[ -e $directory/$newname ]]; then 
        echo "target already exists, skipping: $oldname -> $newname" 
        continue 
    else 
        mv "$path" "$directory/$newname" 
    fi 
    
  8. La tonelada de sed 's/------------/-/g' llamadas se puede cambiar a una sola expresión regular:

    sed -r 's/-{2,}/-/g' 
    
  9. Los [ ] s en tr [foo] [bar] son innecesarias. Solo causan tr para reemplazar [ a [ y ] a ].

  10. ¿No es esto?

    echo "$FOLDERNAME" | sed "s/$/\//g" 
    

    ¿Qué le parece esto?

    echo "$FOLDERNAME/" 
    

Y, por último, utilizar detox.

+6

+10 solo para enfrentar ese desastre. +10 para la desintoxicación. Desafortunadamente, 'tr' no maneja Unicode tampoco. Mientras 'grep' entiende las clases de equivalencia (' [[= a =]] 'coincide con 'aàâãäå'), ni' sed', 'tr' o' gawk' parecen hacerlo. –

+0

@Dennis: GNU 'sed' admite' [[= a =]] '. – grawity

6

Pruebe algo como:

find . -print0 -type f | awk 'BEGIN {RS="\x00"} { printf "%s\x00", $0; gsub("[^[:alnum:]]", "-"); printf "%s\0", $0 }' | xargs -0 -L 2 mv 

El uso de xargs (1) se asegurará de que cada nombre de archivo pasa exactamente como un parámetro. awk (1) se usa para agregar un nuevo nombre de archivo justo después del anterior.

Un truco más: sed -e 's/- +/-/g' reemplazará grupos de más de uno "-" con exactamente uno.

+2

De acuerdo, ese es un uso sexy de awk y xargs. – MikeyB

1

Uf ...

Algunos consejos para limpiar su guión:

** Uso del sed de hacer la traducción en múltiples personajes a la vez, que va a limpiar las cosas y hacer que sea más fácil de manejar:

dev:~$ echo 'áàaieeé!.txt' | sed -e 's/[áàã]/a/g; s/[éè]/e/g' 
aaaieee!.txt 

** en lugar de cambiar el nombre del archivo para cada cambio, se ejecutan todos los filtros y luego hacer un movimiento

$ NEWNAME='áàaieeé!.txt' 
$ NEWNAME="$(echo "$NEWNAME" | sed -e 's/[áàã]/a/g; s/[éè]/e/g')" 
$ NEWNAME="$(echo "$NEWNAME" | sed -e 's/aa*/a/g')" 
$ echo $NEWNAME 
aieee!.txt 

** en lugar de hacer un bucle ls | read ..., utilice:

for OLDNAME in $DIR/*; do 
    blah 
    blah 
    blah 
done 

** separar su recorrido de ruta y el cambio de nombre de la lógica en dos guiones. Una secuencia de comandos encuentra los archivos que necesitan ser renombrados, una secuencia de comandos maneja la normalización de un solo archivo. Una vez que aprenda el comando 'buscar', se dará cuenta de que puede lanzar el primer script :)

+0

Quizás quise decir "para OLDNAME en" $ DIR "/ * – marco

+0

@marco: llámalo pseudocódigo :) En realidad lo eliminé tratando de recordar cómo solucionar el error de reducción de bloque de código en la lista. – MikeyB

Cuestiones relacionadas