GNU/Linux >> Tutoriales Linux >  >> Linux

¿Por qué `zip` en un bucle For funciona cuando el archivo existe, pero no cuando no existe?

Tengo un directorio que contiene varios subdirectorios. Hay una pregunta sobre cómo comprimir los archivos que contiene una respuesta que modifiqué ligeramente para mis necesidades.

for i in */; do zip "zips/${i%/}.zip" "$i*.csv"; done

Sin embargo, me encuentro con un problema extraño. Para el primer conjunto de carpetas, donde zips/<name>.zip no existe, me sale este error:

zip error: Nothing to do! (zips/2014-10.zip)
        zip warning: name not matched: 2014-11/*.csv

sin embargo cuando solo echo las declaraciones postales:

for i in */; do echo zip "zips/${i%/}.zip" "$i*.csv"; done

Luego ejecute el comando repetido (zip zips/2014-10.zip 2014-10/*.csv ), funciona bien y cierra la carpeta. Entonces, la parte divertida de eso es que las ejecuciones posteriores del comando original se ¡realmente comprima las carpetas que no funcionaron la primera vez!

Para probar este comportamiento usted mismo:

cd /tmp
mkdir -p 2016-01 2016-02 2016-03 zips
for i in 2*/; do touch "$i"/one.csv; done
for i in 2*/; do touch "$i"/two.csv; done
zip zips/2016-03.zip 2016-03/*.csv
for i in 2*/; do echo zip "zips/${i%/}.zip" "$i*.csv"; done
for i in 2*/; do zip "zips/${i%/}.zip" "$i*.csv"; done

Verá que el eco imprime estas declaraciones:

zip zips/2016-01.zip 2016-01/*.csv
zip zips/2016-02.zip 2016-02/*.csv
zip zips/2016-03.zip 2016-03/*.csv

Sin embargo, el comando zip real le dirá:

        zip warning: name not matched: 2016-01/*.csv

zip error: Nothing to do! (zips/2016-01.zip)
        zip warning: name not matched: 2016-02/*.csv

zip error: Nothing to do! (zips/2016-02.zip)
updating: 2016-03/one.csv (stored 0%)
updating: 2016-03/two.csv (stored 0%)

Entonces, en realidad está actualizando el archivo zip con .csv s donde existe el archivo zip, pero no cuando se crea el archivo zip. Y si copia uno de los comandos zip:

$ zip zips/2016-02.zip 2016-02/*.csv
adding: 2016-02/one.csv (stored 0%)
adding: 2016-02/two.csv (stored 0%)

Luego vuelva a ejecutar zip-all-the-things:

for i in 2*/; do zip "zips/${i%/}.zip" "$i*.csv"; done

Verás que se actualiza para 2016-02 y 2016-03 . Aquí está mi salida de tree :

.
├── 2016-01
│   ├── one.csv
│   └── two.csv
├── 2016-02
│   ├── one.csv
│   └── two.csv
├── 2016-03
│   ├── one.csv
│   └── two.csv
└── zips
    ├── 2016-02.zip
    └── 2016-03.zip

Además, (no)sorprendentemente, esto funciona bien:

zsh -c "$(for i in 2*/; do echo zip "zips/${i%/}.zip" "$i*.csv"; done)"

¿Qué estoy haciendo mal aquí? (nota, estoy usando zsh en lugar de bash, si eso hace alguna diferencia)

Respuesta aceptada:

Expansión por el caparazón

Las comillas alrededor de "$i*.csv" Haz la diferencia. Con las comillas, el shell expande esa cadena a "2014-11/*.csv". Ese archivo exacto no existe, y zip informa de un error. Sin comillas, el * también se expande (a través de la expansión del nombre de archivo/”globbing”), y el zip resultante comando es una lista completa de archivos coincidentes, cada uno como un argumento separado. Puede obtener el segundo comportamiento, dentro de for bucle, con:

for i in */ ; do zip "zips/${i%/}.zip" "$i"*.csv ; done

Expansión por zip

zip también puede expandir comodines por sí mismo, pero no en todas las situaciones. Del manual zip:

El zip El programa puede hacer la misma coincidencia con los nombres que están en el zip archivo que se está modificando o, en el caso de -x (excluir) o -i (incluir) opciones, en la lista de archivos en los que se va a operar, mediante el uso de barras invertidas o comillas para indicarle al shell que no haga la expansión del nombre.

El comando original funciona en los intentos posteriores, después de haber creado un archivo con éxito, porque zip intenta hacer coincidir los comodines con el contenido del archivo existente. Existen allí y aún existen en el sistema de archivos, por lo que se informan con updating: .

Para obtener zip para manejar los comodines al crear el archivo, use el -r (recurse) opción para recurrir al directorio solicitado, y -i (incluir) para limitarlo a archivos que coincidan con el patrón:

 for i in */ ; do zip -r "zips/${i%/}.zip" "$i" -i '*.csv' ; done

Linux
  1. ¿Por qué la expresión regular funciona en X pero no en Y?

  2. ¿Por qué The Bash Script no reconoce los alias?

  3. ¿Por qué no funciona ~/.bash_profile?

  4. ¿Por qué la sustitución del proceso Bash no funciona con algunos comandos?

  5. ¿El comando Shuf File> File deja un archivo vacío, pero comandos similares no?

¿Por qué `exit &` no funciona?

¿Núcleo volcado, pero el archivo principal no está en el directorio actual?

¿Por qué Tomcat funciona con el puerto 8080 pero no con el 80?

¿Por qué rsync no usa transferencia delta para archivos locales?

¿Por qué 'dd' no funciona para crear un USB de arranque?

¿Por qué wget'ing una imagen me da un archivo, no una imagen?