Zip todos los archivos en el directorio?

483

¿Hay alguna manera de comprimir todos los archivos en un directorio dado con el zipcomando? He oído hablar del uso *.*, pero también quiero que funcione para archivos sin extensión.

tkbx
fuente
2
¿Has intentado navegar un nivel hacia arriba desde tu directorio deseado y hacerlo zip myarch.zip mydir/*?
Joseph R.
13
o mejorzip -r myarch.zip mydir/*
Adam
25
o mejorzip -r myarch.zip mydir
ctrl-alt-delor
*.*significa cualquier archivo con un punto. En cp / my dos todos los archivos tenían un punto, y te hizo escribirlo (no se pudo hacer *). Por lo tanto, la gente llegó a ver *.*como todos los archivos. Finalmente, Microsoft agregó nombres de archivo largos que podrían tener cero o más puntos. Para buscar un archivo que tenga un punto en Windows, debe escribir *.*.*.
ctrl-alt-delor

Respuestas:

705

Solo puedes usar *; no hay necesidad de *.*. Las extensiones de archivo no son especiales en Unix. *coincide con cero o más caracteres, incluido un punto. Entonces coincide foo.png, porque eso es cero o más caracteres (siete, para ser exactos).

Tenga en cuenta que, *de forma predeterminada, no coincide con los archivos que comienzan con un punto (tampoco lo hace *.*). Esto es a menudo lo que quieres. Si no, en bash, si shopt -s dotgloblo hará (pero aún excluirá .y ..). Otros shells tienen diferentes formas (o ninguna) de incluir archivos de puntos.

Alternativamente, ziptambién tiene una -ropción (recursiva) para hacer árboles de directorios completos a la vez (y no tener que preocuparse por el problema del archivo de puntos):

zip -r myfiles.zip mydir

donde mydirestá el directorio que contiene tus archivos. Tenga en cuenta que el zip producido contendrá la estructura del directorio, así como los archivos. Como señala Peter en su comentario, esto generalmente se ve como algo bueno: extraer el zip almacenará perfectamente todos los archivos extraídos en un subdirectorio.

También puede decirle a zip que no almacene las rutas con la opción -j/ --junk-paths.

El zipcomando viene con documentación que le informa sobre todas sus (muchas) opciones; escriba man zippara ver esa documentación. Esto no es exclusivo de zip; Puede obtener documentación para la mayoría de los comandos de esta manera.

derobert
fuente
99
Es posible que desee agregar, que se considera una buena práctica contener todo en el archivo en un directorio de nivel superior, para que uno no contamine su directorio actual en la extracción.
Peter
@peterph hecho. Aunque esto es menos una convención en archivos zip que en, por ejemplo, tarfiles, me temo.
derobert
por desgracia sí. Probablemente debido a la herencia de Windows de arrastrar y soltar al escritorio y la herencia de Linux de trabajar con códigos fuente.
Peter
2
Tenga en cuenta que *el bloqueo de shell no incluye archivos de puntos (es decir, nombres de archivo que comienzan con .). Esta es otra ventaja de comprimir todo el directorio por su nombre.
mrb
Pero el uso de -r incluye el directorio en sí, que rompe lo que estoy haciendo. ¿No incluiría .y ..?
tkbx
11

En mi caso, quería comprimir cada archivo en su propio archivo, así que hice lo siguiente (en zsh):

$ for file in *; do zip ${file%.*}.zip $file; done
Radon Rosborough
fuente
1
No hay mkvaqui? Además, nada aquí es particularmente zshespecífico. Deberá citar correctamente cualquier variable que contenga un nombre de archivo, por lo tanto, zip "${file%.*}.zip" "$file"con las comillas dobles alrededor de ambas variables.
tripleee
1
@tripleee En primer lugar, gracias por señalar mi referencia errónea a mkv. En segundo lugar, es innecesario citar argumentos zsh, a diferencia de bash. Es por eso que especifiqué que este era un comando para zsh.
Radon Rosborough
Reemplazar el último punto y coma con un ampersand podría acelerarlo significativamente (si el número de archivos en el directorio es razonable ...). De lo contrario find . -type f -maxdepth 1 -print0|xargs -r0 -n1 -P64 -I{} bash -c 'f="{}"; zip "${f%.*}.zip" "$f"'( -Pajustado según los hilos de su CPU ...) (Muchas dependencias de GNU ...)
Gert van den Berg
5

Otra forma sería usar find y xargs: (esto podría incluir un directorio "." En el zip, pero aún así debería extraerse correctamente. Con mi prueba, zip eliminó el punto antes de la compresión) find . -type f -exec zip zipfile.zip {} +

(Se +puede reemplazar con \;si su versión de findno admite el +final para exec. Sin embargo, será más lento ...)

Esto incluirá por defecto todos los subdirectorios. En GNU find -maxdepthpuede evitar eso.

Gert van den Berg
fuente
(a diferencia de las soluciones que utilizan *, esto incluirá archivos de puntos y no se caerá si hay demasiados archivos en un directorio)
Gert van den Berg
1

Otro método (lento) para hacer esto (que agrega un archivo al zip a la vez):

for f in * .[^.]*; do
    [ -r "$f" ] || continue # Skip directories or non-existant files (Probably ".[^.]*" if directory has no dotfiles). Using -e will allow directories to be used as well
    zip zipfile.zip "$f" # If directories are included, you probably want to add -r
done

Esto tiene los problemas de *archivo de puntos de (solución agregada) y se iniciará zip una vez para cada archivo, agregándolo al archivo. En bash, trataría con una gran cantidad de archivos.

Sería más lento que la mayoría de los otros métodos, pero es relativamente simple.

Gert van den Berg
fuente
1
Yo diría que esto es menos simple que la respuesta aceptada, y más lento, lo que lleva a la pregunta: "¿Por qué alguien haría esto?". Si puede responder esa pregunta, le recomiendo que ponga ese contexto en su respuesta, de lo contrario creo que es una mala respuesta a una pregunta anterior que ya tiene una buena respuesta.
Centimane
@ Centimane: Tomo nota de las limitaciones. Siento que esto tiene valor educativo. (Si no se saltan directorios, es bastante simple). Si desea una respuesta mucho más rápida utilizando una herramienta externa (estándar), mi otra respuesta cubre eso. (con el manejo de los archivos de puntos eliminado (lo que afecta la corrección sin su ausencia mencionada en la pregunta), creo que es bastante elegante):for f in *; do zip zip.zip "$f"; done
Gert van den Berg
1
Tenga en cuenta que la respuesta aceptada no utiliza un comando externo y sería más rápido. ¿En qué escenario sería útil esta respuesta?
Centimane
@Centimane Con tar cuando hay más archivos de los que bash puede pasar como parámetros. (find + xargs son mejores, porque los bucles son más fáciles ...). Es una respuesta (única) a la pregunta. Ciertamente no es la respuesta óptima. (Las respuestas no óptimas aún pueden ser útiles para problemas similares, si alguien tiene una situación ligeramente diferente, por ejemplo, si desea un archivo tar en cualquier directorio)
Gert van den Berg