Bash: nombre de archivo a nombre de archivo, coincidencia incorrecta (zip, cdg, mp3)

Dec 07 2020

He escrito un script que busca dos extensiones particulares en un archivo zip. Se realizan un par de comprobaciones que determinan si el archivo tiene solo 2 archivos y luego los procesa. Si el archivo tiene menos de 2, lo moverá a una carpeta "MALO". Si el archivo tiene más de 2, lo moverá a un directorio "FIX".

El paso del proceso es extraer los archivos y cambiarles el nombre por el mismo nombre que tiene el archivo zip.

Todo esto funciona bien, cuando las condiciones son perfectas. Pero cuando no son perfectos ... se pone feo.

Me encuentro con un caso en el que, aunque los archivos pueden tener los 2 archivos y la extensión correctos, si los archivos tienen caracteres especiales (como Ø, comillas, coma, apóstrofo, etc.) ... se procesan (supongo) como expresiones o sintaxis de expresiones regulares.

Aquí está el código:

#! /bin/bash

prefix="0000_"

mkdir -p ${prefix}{DONE,FIX,BAD} shopt -s nocaseglob for i in *.ZIP; do zip_name="$i"
        pair_exists=$(unzip -Z1 "$i" | grep -E -- '.cdg|.CDG|.mp3|.MP3' | wc -l)
        log="${prefix}LOG.txt" if [ $pair_exists -eq 2 ]
            then
                cdg_name=$(unzip -Z1 "$i" | grep -E -- '.cdg|.CDG' | awk '{print substr($0,index($0,$1))}') mp3_name=$(unzip -Z1 "$i" | grep -E -- '.mp3|.MP3' | awk '{print substr($0,index($0,$1))}')
                new_cdg_name="$(echo "${zip_name%.*}.cdg")"
                new_mp3_name="$(echo "${zip_name%.*}.mp3")"
                7za x "$i" -aoa -y -ba >> ./$log
                mv ./"$cdg_name" ./"$new_cdg_name"
                mv ./"$mp3_name" ./"$new_mp3_name"
                mv ./"$zip_name" ./${prefix}DONE/

        elif [ $pair_exists -gt 2 ] then echo "" echo "NEEDS FIXED: $zip_name"
                mv ./"$zip_name" ./${prefix}FIX/

        elif [ $pair_exists -lt 2 ] then echo "" echo "ARCHIVE IS BAD: $zip_name"
                mv ./"$zip_name" ./${prefix}BAD/

        else
                echo ""
                echo "MUST BE BROKE!"
                echo ""
        fi
    done
exit

Todo está bien, hasta que llego a las declaraciones de mv.

                mv ./"$cdg_name" ./"$new_cdg_name"
                mv ./"$mp3_name" ./"$new_mp3_name"

Creo que quizás mv no sea el método correcto para usar aquí, pero también estaba teniendo serios problemas con el cambio de nombre. Creo más que necesito un código que le diga a los comandos que no traten ningún carácter dentro de las variables como acciones a realizar.

Esto es lo que veo que está pasando ...

----- EJEMPLO 1 -----

NOMBRE DEL ARCHIVO ZIP: 

     CB30035-05 - PLAN SIMPLE - HARÍA CUALQUIER COSA.zip

ARCHIVOS DENTRO DEL ZIP:

     CB30035-05 - Plan simple - Haría cualquier cosa.cdg
     CB30035-05 - Plan simple - Haría cualquier cosa.mp3

ERROR:

     mv: can't stat './CB30035-05 - Simple PlanI \' do Anything.cdg ': No existe tal archivo o directorio
     mv: can't stat './CB30035-05 - Simple PlanI \' do Anything.mp3 ': No existe tal archivo o directorio

----- EJEMPLO 2 -----

NOMBRE DEL ARCHIVO ZIP:

     CBSE5-0068 - CARPINTEROS, EL - POR TODO LO QUE SABEMOS.zip

ARCHIVOS DENTRO DEL ZIP:

     cbscdge450-5-0068 - Carpinteros - Por todo lo que sabemos.cdg
     cbscdge450-5-0068 - Carpinteros - Por todo lo que sabemos.mp3

ERROR:
mv: can't stat './cbscdge450-5-0068 - Carpenters - For All We Know.cdg \ ncbscdge450-5-0068 - Carpenters - For All We Know.mp3': No existe tal archivo o directorio

He buscado un problema similar, pero los temas que encontré no encajaban realmente con mi problema o parte del código estaba un poco sobre mi cabeza para tratar de descubrir cómo incorporarlos a mi script.

Apreciaría cualquier ayuda. ¡Gracias!

(NOTA: Soy consciente de que mi "awk" en el script anterior no está haciendo nada. Me moví a "descomprimir -Z1" y eso parece haber resuelto mis esfuerzos anteriores para obtener el nombre de archivo de los archivos zip. Me he dejado y lo ajusté solo para mantenerlo en caso de que lo necesite.)



EDITAR 2020120601:


En respuesta a @Wieland, eliminé el doble espacio del nombre del archivo zip. Pero dejó el doble espacio en los archivos adentro. No podré arreglar el interior de cada archivo, ya que hay muchos, así que necesito averiguar cómo arreglarlos como están. La eliminación del doble espacio en el archivo zip no cambió mis resultados.

En respuesta a @steeldriver, aquí hay un poco más de información. A continuación se muestra el resultado de cada uno de los comandos que he intentado usar (observe el 7za ... no tiene una forma de producir nombres de archivos, por lo que estaba usando awk anteriormente).

También cambié el código para leer y esto no cambió mis resultados, pero estoy de acuerdo en cubrir esa base.\.cdg$|\.CDG$|\.mp3$|\.MP3$

zipinfo -1 "CB30035-05 - PLAN SIMPLE - HARÍA CUALQUIER COSA.zip" 

  CB30035-05 - Plan simple: haría cualquier cosa.cdg
  CB30035-05 - Plan simple, haría cualquier cosa.mp3

descomprimir -Z1 "CB30035-05 - PLAN SIMPLE - HARÍA CUALQUIER COSA.zip" 

  CB30035-05 - Plan simple: haría cualquier cosa.cdg
  CB30035-05 - Plan simple, haría cualquier cosa.mp3

7za -ba l "CB30035-05 - PLAN SENCILLO - HARÍA CUALQUIER COSA.zip"           

   2003-06-27 14:41:56 .... A 1516512 379652 CB30035-05 - Plan simple, haría cualquier cosa.cdg
   2003-06-27 14:42:22 .... A 3369876 3112004 CB30035-05 - Simple PlanI'd Do Anything.mp3



EDITAR 2020120701:


@ G-Man dice 'Reincorporar a Monica'

Gracias por envolver tantos detalles en sus explicaciones. Soy consciente de que. Incorporaré sus modificaciones sugeridas al scripting. En lo que respecta a

Si "cambió el código para leer .cdg$|.CDG$| .mp3$|.MP3$ y esto no cambió mis resultados ”, entonces lo hiciste mal ...

Estoy bastante seguro de que seguí tu ejemplo de cerca. Había comentado diciendo que hice eso, pero la barra invertida fue eliminada de mi comentario. También ya había implementado el grep "c". Pero aparentemente se perdió la opción "i". Eso definitivamente limpiaría eso.

Aquí está el código tal como está ahora ...

#! /bin/bash

prefix="00001_"

mkdir -p ${prefix}{DONE,FIX,BAD} shopt -s nocaseglob for i in *.ZIP; do zip_name="$i"
        pair_exists=$(unzip -Z1 "$i" | grep -Eci -- '\.cdg$|\.mp3$')

        if [ $pair_exists -eq 2 ] then cdg_name=$(unzip -Z1 "$i" | grep -E -- '\.cdg$|\.CDG$') mp3_name=$(unzip -Z1 "$i" | grep -E -- '\.mp3$|\.MP3$') base_name="${zip_name%.*}"
                new_cdg_name="$base_name.cdg" new_mp3_name="$base_name.mp3"

                        printf 'cdg_name = [%s]\n' "$cdg_name" printf 'mp3_name = [%s]\n' "$mp3_name"

                unzip -qq "$i" mv -- "${cdg_name}" "${new_cdg_name}" mv -- "${mp3_name}" "${new_mp3_name}" mv ./"$zip_name" ./${prefix}DONE/ elif [ $pair_exists -gt 2 ]
            then
                echo ""
                echo "NEEDS FIXED: $zip_name" mv ./"$zip_name" ./${prefix}FIX/ elif [ $pair_exists -lt 2 ]
            then
                echo ""
                echo "ARCHIVE IS BAD: $zip_name" mv ./"$zip_name" ./${prefix}BAD/

        else
                echo ""
                echo "HMM"
                echo ""
        fi
    done
exit

También incorporé tus cambios.

Con respecto a una depuración, una vez más había usado "echo". Esto es lo que está en mi script de prueba ...

echo ""
echo "-----"
echo   $pair_exists
echo   $zip_name echo $cdg_name
echo   $mp3_name echo $new_cdg_name
echo   $new_mp3_name echo $prefix
echo   $log
echo "-----"
echo ""

Producía lo mismo que tu "printf". Sin embargo, me gustan mucho tus formas elegantes y adoptaré tu estilo. :)

Para responder al punto 5. Tuve esa idea al usar 7z.exe. En realidad, mirándolo a través de una GUI. Ahora voy a publicar una captura de pantalla de lo que ve mi caja de Windows y nuevamente publicaré lo que produce mi caja de Linux.

VENTANAS :

LINUX :

NO TENGO PISTA de por qué está sucediendo eso. Después de mirar eso por un tiempo, una parte de mí piensa que tal vez ... De alguna manera arruiné mi entorno. No había cruzado un problema como este antes, ¡y me deja tirándome de los pelos!

¡AHORA! Habiéndote dado toda esta información, y tal vez no te haya dado la suficiente. Pero necesito decirte. Después de haber realizado sus cambios en el código, ¡está produciendo el resultado correcto! Aunque mi sistema aún elimina el "-" de los nombres de archivo, está produciendo el resultado final deseado. Quería que los archivos tomaran el nombre del archivo zip y eso es lo que está haciendo ahora.

Los cambios que hice ...

  1. limpió el par_existe con
    unzip -Z1 "$i" | grep -Eci -- '\.cdg$|\.mp3$'

  2. limpie la extracción cdg y mp3_name y eliminó el awk
    cdg_name=$(unzip -Z1 "$i" | grep -E -- '\.cdg$|\.CDG$')
    mp3_name=$(unzip -Z1 "$i" | grep -E -- '\.mp3$|\.MP3$')

  3. incorporó la nueva sugerencia de base_name y la eliminación de echo
    base_name="${zip_name%.*}"
    new_cdg_name="$base_name.cdg"
    new_mp3_name="$base_name.mp3"

  4. agregó las líneas de depuración "printf" (las comentará cuando haga 150k + archivo)
    printf 'cdg_name = [%s]\n' "$cdg_name"
    printf 'mp3_name = [%s]\n' "$mp3_name"

  5. Cambio el descompresor para descomprimir para mantener la coherencia con el conjunto de herramientas
    unzip -qq "$i"

No sé dónde ocurrió la solución, pero realmente agradezco su ayuda. @ G-Man dice 'Reincorporar a Mónica' y ayudarme a superar esto y dar algunos consejos muy sólidos.

¡Gracias!


Respuestas

1 G-ManSays'ReinstateMonica' Dec 07 2020 at 21:17
  1. Es casi seguro que el comentario de Steeldriver identifica parte del problema. Si "cambió el código para leer y esto no cambió mis resultados", entonces lo hizo mal, específicamente, lo hizo de manera incompleta. Parte del problema radica en el comando\.cdg$|\.CDG$|\.mp3$|\.MP3$

    cdg_name=$(unzip -Z1 "$i" | grep -E -- '.cdg|.CDG' | awk '{print substr($0,index($0,$1))}')
    

    que debe cambiarse a

    cdg_name=$(unzip -Z1 "$i" | grep -E -- '\.cdg$|\.CDG$' | awk '{print substr($0,index($0,$1))}')
    

    porque coincide , y así se establece la concatenación de ambos nombres , separados por una nueva línea.   Esto queda bastante claro en el mensaje de error.cbscdge450-5-0068 - Carpenters ….cdgcdg_namemv

  2. Solo con fines de simplificación, puede cambiar

    unzip -Z1 "$i" | grep -E -- '\.cdg$|\.CDG$|\.mp3$|\.MP3$' | wc -l
    

    a

    unzip -Z1 "$i" | grep -Ec -- '\.cdg$|\.CDG$|\.mp3$|\.MP3$'
    

    (utilizando el c opción porte de grep) o incluso

    unzip -Z1 "$i" | grep -Eci -- '\.cdg$|\.mp3$'
    

    (usando la opción i gnore case de grep).

  3. Casi nunca hay razón para decirlo . De hecho, me inclino a decir que nunca hay una razón para hacer eso, pero alguien probablemente identificará un caso extraño en el que es beneficioso. Específicamente,$(echo "something")

    new_cdg_name="$(echo "${zip_name%.*}.cdg")"
    new_mp3_name="$(echo "${zip_name%.*}.mp3")"
    

    se puede cambiar a

    new_cdg_name="${zip_name%.*}.cdg" new_mp3_name="${zip_name%.*}.mp3"
    

    Incluso podría ir tan lejos como para cambiarlos a

    base_name="${zip_name%.*}" new_cdg_name="$base_name.cdg"
    new_mp3_name="$base_name.mp3"
    

    PD Estrictamente hablando, las citas de arriba no son necesarias, pero es una buena práctica usarlas todo el tiempo a menos que tenga una buena razón para no hacerlo.
    PPS En el contexto incorrecto, podría hacer cosas como cambiar a (es decir, comprimir varios espacios en uno).$(echo "something")Plan  - IPlan - I

  4. A riesgo de ser políticamente incorrecto, imagina que eres la policía tratando de resolver un crimen, y que todo lo que puedes hacer es sentarte afuera de la sede de los criminales con binoculares. ¿No sería mucho mejor si pudiera obtener una intervención telefónica o un informante, para saber lo que está sucediendo dentro del edificio? La depuración es como tratar de resolver un delito: si bien la información externa (es decir, la salida de zipinfoy 7za, se ejecuta por separado) es importante para comprender el problema, realmente ayuda a obtener la información interna. Entonces, como un paso de depuración de rutina, recomiendo agregar declaraciones como

    printf 'cdg_name = [%s]\n' "$cdg_name" printf 'mp3_name = [%s]\n' "$mp3_name"
    

    al guión. Esto habría hecho obvio que se cdg_nameestaba configurando para la concatenación de los dos nombres, y podría ayudarlo a rastrear dónde I'd Do Anythingcambia I\'d Do Anything.

  5. Estrictamente hablando, esto debería ser un comentario, pero, mientras esté aquí: ¿de dónde sacaste la idea de que los nombres de los archivos de miembros dentro CB30035-05 - SIMPLE PLAN - I'D DO ANYTHING.ziperan

    • CB30035-05 - Simple Plan - I'd Do Anything.cdg y
    • CB30035-05 - Simple Plan - I'd Do Anything.mp3

    cuando no nos ha mostrado ningún comando que muestre algo entre el  Plany el  I?

  6. Como mencioné anteriormente, I\'d Do Anythinges un rompecabezas. Pero, ¿tiene realmente algún ejemplo de problemas relacionados con comas, comillas inversas o caracteres no ASCII (como 'é', 'Φ', 'Ø', 'θ', '½' o '∞')?