¿Cómo puedo comprimir un archivo en Linux in situ, sin usar espacio de disco adicional?

20

Tengo una unidad de 100 GB que tiene un archivo de 95 GB. Necesito liberar algo de espacio en la unidad (y en este momento transferir el archivo fuera de la unidad no es una opción). El archivo se comprimiría bien con gzipo bz2o lo que sea, pero todos estos programas escriben el archivo comprimido en un archivo separado. No tengo suficiente espacio libre para esto.

¿Hay alguna forma de usar herramientas de compresión estándar u otras utilidades de Unix para comprimir el archivo sin usar espacio en disco adicional (o al menos una cantidad mínima de espacio en disco adicional)? Me imagino algo que comprime parte del archivo a la vez y escribe los resultados directamente sobre el archivo. Me doy cuenta de que esto sería arriesgado, ya que el archivo se dañaría si se interrumpiera la compresión, pero no creo que tenga otra opción.

Sotavento
fuente
Una última opción que solíamos usar en mi antiguo lugar era tener un directorio en algún lugar que contuviera un montón de archivos 1G llenos de basura. Luego, si tiene problemas, puede eliminar algunos de ellos para darle un poco de espacio de emergencia.

Respuestas:

13

Esta es una prueba de concepto bash one-liner, pero debería ayudarlo a comenzar. Úselo bajo su propio riesgo.

truncate -s `gzip -c file | dd of=file conv=notrunc 2>&1 | sed -n '$ s/ .*$// p'` file
mv file file.gz

Esto funciona canalizando datos gz a un proceso dd que los vuelve a escribir en el mismo archivo. Al finalizar, el archivo se trunca al tamaño de la salida gz.

Esto supone que la última línea de salida de dd coincide:

4307 bytes (4.3 kB) copiados, 2.5855e-05 s, 167 MB / s

Donde el primer campo es un entero de bytes escritos. Este es el tamaño al que deberá truncarse el archivo. No estoy 100% seguro de que el formato de salida sea siempre el mismo.

usuario710307
fuente
Ingenioso truco. ¿Podría explicar por qué conv=notrunces necesario?
sleske
Quizás no lo sea. gzip -c file | dd of=fileparece funcionar igual de bien.
user710307
1
La gente en la pregunta vinculada lo intentó (y yo también lo intenté); No funciona en general. Parece que solo funciona para archivos muy pequeños, tal vez porque gzip leerá un archivo pequeño en la RAM antes de comprimirlo. Para archivos grandes (unos pocos MB), no funciona, incluso si son comprimibles.
sleske
3
Sí. Entonces conv = notrunc es necesario.
user710307
1
¿No es posible que en algún momento el programa de compresión (p gzip. Ej. ) Escriba más bytes de encabezado y datos que los bytes de datos originales, sobrescribiendo así algunas partes del archivo? Supongo que esto depende del programa de compresión elegido. ¿Alguien tiene una idea de cómo evitar que esto suceda o cuán (im) probable es?
Daniel Böhmer
7

No es tanto eso gzipy bzip2sobrescribir el original. Por el contrario, escriben los datos comprimidos en el disco como un nuevo archivo, y si esa operación tiene éxito, desvinculan el archivo original sin comprimir.

Si tiene suficiente RAM, puede escribir un script para comprimir temporalmente los archivos en un tmpfssistema de archivos, luego eliminar el original en el disco y reemplazarlo con la versión comprimida. Tal vez algo como esto:

# some distributions mount /dev/shm as tmpfs; replace with bzip2 if you prefer
if gzip -q9c /full/disk/somefile > /dev/shm/somefile.gz
then
    rm -f /full/disk/somefile && mv -i /dev/shm/somefile.gz /full/disk
fi

Solo tenga en cuenta su uso de memoria, ya que tmpfses esencialmente un disco RAM. Un archivo de salida grande podría matar de hambre fácilmente al sistema y causarle otros problemas.

James Sneeringer
fuente
1
Eso es lo suficientemente loco como para funcionar
Andrew Lambert el
Me gusta empujar el sobre.
James Sneeringer
3

No existe una herramienta que funcione de esta manera, precisamente por la razón que da. Pocas personas están dispuestas a escribir una herramienta que implemente deliberadamente comportamientos riesgosos.

Ignacio Vazquez-Abrams
fuente
Esperaba que fuera una opción insegura y no predeterminada para una utilidad. ¿Se te ocurre una alternativa? ¿Hay alguna manera de truncar un archivo para, por ejemplo, eliminar los primeros 2 GB? Eso me permitiría usar mi espacio libre limitado para comprimir un fragmento a la vez, reduciendo el archivo fuente a medida que avanzaba.
Lee
Realmente no hay una forma sensata de eliminar datos desde el comienzo de un archivo en ningún sistema de archivos, con ninguna herramienta.
Ignacio Vazquez-Abrams
2
Pero puede eliminar datos del final del archivo. Se puede hacer en principio. Corta los datos del final del archivo para colocarlos en archivos separados, truncando los archivos originales a medida que avanza. Luego comprime los archivos en orden hacia adelante, eliminándolos a medida que avanza. Sería una tarea difícil de implementar y si algo saliera mal, estarías jodido. Pero es posible.
David Schwartz
1

Los comandos split y csplit podrían usarse para dividir el archivo grande en partes más pequeñas y luego comprimirlos individualmente. Sin embargo, volver a ensamblar llevaría bastante tiempo.

Brian
fuente
Otra buena opcion. Probablemente se podría escribir un guión para hacer esto. Sin embargo, esto produce muchos archivos comprimidos por separado, que deberán volver a concatenarse después de descomprimir, lo que no es tan bueno.
sleske