Comment puis-je compresser un fichier sur Linux sur place, sans utiliser d'espace disque supplémentaire?

20

J'ai un lecteur de 100 Go contenant un fichier de 95 Go. J'ai besoin de libérer de l'espace sur le lecteur (et pour le moment, le transfert du fichier hors du lecteur n'est pas une option). Le fichier se comprimerait bien avec gzipou bz2ou autre chose, mais tous ces programmes écrivent le fichier compressé dans un fichier séparé. Je n'ai pas assez d'espace libre pour cela.

Existe-t-il un moyen d'utiliser des outils de compression standard ou d'autres utilitaires Unix pour compresser le fichier sans utiliser d'espace disque supplémentaire (ou au moins une quantité minimale d'espace disque supplémentaire)? J'imagine quelque chose qui comprime une partie du fichier à la fois et écrit les résultats directement sur le fichier. Je me rends compte que ce serait risqué, car le fichier serait corrompu si la compression était interrompue, mais je ne pense pas avoir le choix.

Lee
la source
Une dernière option que nous utilisions à mon ancien endroit était d'avoir un répertoire quelque part qui contenait tout un tas de fichiers 1G remplis de déchets. Ensuite, si vous êtes pris dans un pincement, vous pouvez en retirer certains pour vous donner un peu d'espace d'urgence.

Réponses:

13

C'est une preuve de concept bash one-liner, mais elle devrait vous aider à démarrer. À utiliser à vos risques et périls.

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

Cela fonctionne en redirigeant les données gz vers un processus dd qui les réécrit dans le même fichier. Une fois terminé, le fichier est tronqué à la taille de la sortie gz.

Cela suppose que la dernière ligne de la sortie de dd correspond:

4307 octets (4,3 ko) copiés, 2,5855e-05 s, 167 Mo / s

Où le premier champ est un entier d'octets écrits. Il s'agit de la taille à laquelle le fichier devra être tronqué. Je ne suis pas sûr à 100% que le format de sortie soit toujours le même.

user710307
la source
Astuce astucieuse. Pourriez-vous expliquer pourquoi conv=notruncest nécessaire?
sleske
Peut-être que non. gzip -c file | dd of=filesemble fonctionner aussi bien.
user710307
1
Les gens à la question liée l'ont essayé (et je l'ai aussi essayé); cela ne fonctionne pas en général. Il semble que cela ne fonctionne que pour les très petits fichiers - peut-être parce que gzip lira un petit fichier dans la RAM avant de le compresser. Pour les gros fichiers (quelques Mo), cela ne fonctionne pas, même s'ils sont compressibles.
sleske
3
Oui. Donc conv = notrunc est nécessaire.
user710307
1
N'est-il pas possible qu'à tout moment le programme de compression (par exemple gzip) écrit plus d'en-têtes et d'octets de données que les octets de données d'origine, écrasant ainsi certaines parties du fichier? Je suppose que cela dépend du programme de compression choisi. Quelqu'un a-t-il une idée de la façon d'empêcher que cela se produise ou de la probabilité (im) probable de cela?
Daniel Böhmer
7

Ce n'est pas tant que ça gzipet bzip2écraser l'original. Au lieu de cela, ils écrivent les données compressées sur le disque en tant que nouveau fichier et si cette opération réussit, ils dissocient le fichier non compressé d'origine.

Si vous avez suffisamment de RAM, vous pouvez écrire un script pour compresser temporairement les fichiers dans un tmpfssystème de fichiers, puis supprimer l'original sur le disque et le remplacer par la version compressée. Peut-être quelque chose comme ça:

# 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

Gardez simplement à l'esprit votre utilisation de la mémoire, car il tmpfss'agit essentiellement d'un disque RAM. Un fichier de sortie volumineux pourrait facilement affamer le système et causer d'autres problèmes pour vous.

James Sneeringer
la source
1
C'est juste assez fou pour travailler
Andrew Lambert
J'aime pousser l'enveloppe.
James Sneeringer
3

Il n'y a aucun outil qui fonctionne de cette façon, précisément pour la raison que vous donnez. Peu de gens sont prêts à écrire un outil qui met délibérément en œuvre des comportements à risque.

Ignacio Vazquez-Abrams
la source
J'espérais que ce serait une option non sûre et non par défaut pour un utilitaire. Pourriez-vous penser à une alternative? Existe-t-il un moyen de tronquer un fichier en place, par exemple, supprimer les 2 premiers Go? Cela me permettrait d'utiliser mon espace libre limité pour compresser un morceau à la fois, réduisant le fichier source au fur et à mesure.
Lee
Il n'y a vraiment aucun moyen sensé de supprimer des données du début d'un fichier sur n'importe quel système de fichiers, avec n'importe quel outil.
Ignacio Vazquez-Abrams
2
Mais vous pouvez supprimer des données à la fin du fichier. Cela peut être fait en principe. Vous découpez les données à la fin du fichier pour les placer dans des fichiers séparés, en tronquant les fichiers d'origine au fur et à mesure. Ensuite, vous compressez les fichiers dans l'ordre avant, en les supprimant au fur et à mesure. Ce serait pénible à mettre en œuvre et si quelque chose tournait mal, vous seriez foutu. Mais c'est possible.
David Schwartz
1

Les commandes split et csplit peuvent être utilisées pour diviser le gros fichier en parties plus petites, puis les compresser individuellement. Le remontage serait cependant assez long.

Brian
la source
Une autre bonne option. On pourrait probablement écrire un script pour ce faire. Cependant, cela donne de nombreux fichiers compressés séparément, qui devront être reconcatiés après la décompression, ce qui n'est pas si agréable.
sleske