¿Hay alguna forma de comprimir todos los archivos en un directorio determinado con el comando zip
? He oído hablar del uso de *.*
, pero también quiero que funcione para archivos sin extensión.
Comentarios
Respuesta
Puede usar *
; no es necesario para *.*
. Las extensiones de archivo no son especiales en Unix. *
coincide con cero o más canales caracteres, incluido un punto. Entonces coincide con foo.png
, porque eso es cero o más caracteres (siete, para ser exactos).
Tenga en cuenta que *
por defecto no coincide con archivos que comiencen con un punto (tampoco *.*
). Esto es a menudo lo que quieres. De lo contrario, en bash, si shopt -s dotglob
lo hará (pero aún excluirá .
y ..
). Otros shells tienen diferentes formas (o ninguna) de incluir archivos de puntos.
Alternativamente, zip
también tiene un -r
Opció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 mydir
es el directorio que contiene sus archivos. Tenga en cuenta que el zip producido contendrá la estructura del directorio así como los archivos. Como señala peterph en su comentario, esto generalmente se ve como algo bueno: extraer el zip almacenará ordenadamente todos los archivos extraídos en un subdirectorio.
También puede decirle a zip que no almacene las rutas con el -j
/ --junk-paths
opción.
El comando zip
viene con documentación que le informa sobre todas sus (muchas) opciones; escriba man zip
para ver esa documentación. Esto no es exclusivo de zip; puede obtener documentación para la mayoría de los comandos de esta manera.
Comentarios
- Es posible que desee agregar, que es Consideró una buena práctica contener todo el archivo en un directorio de nivel superior, de modo que uno no ‘ t contamine su directorio actual en la extracción.
- @peterph hecho. Aunque esto es menos una convención en archivos zip que en, por ejemplo, tarfiles, ‘ me temo.
- desafortunadamente sí. Probablemente debido a las ventanas herencia de drag ‘ n ‘ soltar en el escritorio y herencia de Linux de trabajar con códigos fuente.
- Mantener en Tenga en cuenta que
*
shell-globbing no ‘ t incluye dotfiles (es decir, nombres de archivo que comienzan con.
). Esta es otra ventaja de comprimir todo el directorio por nombre. - Pero usar -r incluye el directorio mismo, lo que rompe lo que id = «ab8b7445e2»>
estoy haciendo. ¿No incluiría ‘ t *.
y..
?
Respuesta
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
Comentarios
- Hay ‘ ¿no hay
mkv
aquí? Además, nada aquí es particularmentezsh
específico. ‘ querrá citar correctamente cualquier variable que contenga un nombre de archivo, así quezip "${file%.*}.zip" "$file"
con las comillas dobles alrededor de ambas variables. - @tripleee En primer lugar, gracias por señalar mi referencia errónea a
mkv
. En segundo lugar, no es necesario citar argumentos enzsh
, a diferencia debash
. Esa ‘ es la razón por la que especifiqué que este era un comando parazsh
. - Reemplazo del último punto y coma por 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"'
(con-P
ajustado según los subprocesos de su CPU …) (Muchas dependencias GNU …) - para comprimir cada archivo en su propio archivo, haga
gzip *
Responder
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 compresión) find . -type f -exec zip zipfile.zip {} +
(El +
se puede reemplazar con \;
si su versión de find
no es compatible con el +
final para el ejecutivo. Aunque será más lento …)
Esto incluirá por defecto todos los subdirectorios. En GNU find -maxdepth
puede evitar eso.
Comentarios
- (a diferencia de las soluciones que usan
*
, esto incluirá dotfiles y ‘ no se caerá si hay demasiados archivos en un directorio)
Answer
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 dotfile de *
(solución alternativa agregada) y debería iniciar zip una vez para cada archivo, agregándolo al archivo. En bash
, manejaría una gran cantidad de archivos.
Sería más lento que la mayoría de los otros métodos, pero es relativamente simple.
Comentarios
- Yo diría que esto es menos simple que la respuesta aceptada y más lento, lo que genera 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: noto las limitaciones . Siento que esto tiene valor educativo. (Si no se saltan directorios, es bastante sencillo). Si desea una respuesta mucho más rápida utilizando una herramienta externa (estándar), mi otra respuesta cubre eso. (con el manejo de dotfiles 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
- Tenga en cuenta que el aceptado La respuesta no ‘ t usa un comando externo y sería más rápido. ¿En qué escenario sería útil esta respuesta?
- @Centimane Con tar cuando hay más archivos de los que bash puede pasar como parámetros. (buscar + xargs es mejor, 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 algún directorio)
zip myarch.zip mydir/*
?zip -r myarch.zip mydir/*
zip -r myarch.zip mydir
*.*
significa cualquier archivo con un punto. En cp / my dos todos los archivos tenían un punto, y eso te obligaba a escribirlo (no se podía hacer*
). Por lo tanto, la gente vino a ver*.*
como todos los archivos. Finalmente, Microsoft agregó nombres de archivo largos que podrían tener cero o más puntos. Para encontrar un archivo que tenga un punto en Windows, debe escribir*.*.*
.