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