Supposons que j'ai un fichier de 80 Go /root/bigfile
sur un système de 100 Go et que je souhaite mettre ce fichier dans une archive /root/bigarchive.tar
J'ai évidemment besoin de supprimer ce fichier en même temps qu'il est ajouté dans l'archive. D'où ma question:
Comment supprimer un fichier en même temps qu'il est ajouté dans une archive?
tar
zip
compression
gzip
user123456
la source
la source
Une archive tar non compressée d'un seul fichier se compose d'un en-tête, du fichier et d'un tampon de fin. Votre problème principal est donc de savoir comment ajouter 512 octets d'en-tête au début de votre fichier. Vous pouvez commencer par créer le résultat souhaité avec juste l'en-tête:
Copiez ensuite le premier 10G de votre fichier. Pour simplifier, nous supposons que votre dd peut lire / écrire 1Gib à la fois:
Nous désallouons maintenant les données copiées du fichier d'origine:
Cela remplace les données par des zéros épars qui ne prennent pas de place sur le système de fichiers. Continuez de cette manière, en ajoutant un
skip=10
au suivantdd
, puis en incrémentant lefallocate
décalage de départ à-o 10GiB
. À la toute fin, ajoutez des caractères nuls pour compléter le fichier tar final.Si votre système de fichiers ne prend pas en charge,
fallocate
vous pouvez faire quelque chose de similaire, mais en commençant à la fin du fichier. Copiez d'abord les 10 derniers Go du fichier dans un fichier intermédiaire appelé, par exemplepart8
. Utilisez ensuite latruncate
commande pour réduire la taille du fichier d'origine. Procédez de la même manière jusqu'à ce que vous ayez 8 fichiers de 10 Go chacun. Vous pouvez ensuite concaténer l'en-tête etpart1
versbigarchive.tar
, puis le supprimerpart1
, puis le concaténerpart2
et le supprimer, etc.la source
La suppression d'un fichier ne fait pas nécessairement ce que vous pensez qu'il fait. C'est pourquoi dans les systèmes de type UNIX, l'appel système est appelé
unlink
et nondelete
. Depuis la page de manuel:Par conséquent, tant que le compresseur / archiveur de données lit le fichier, ce fichier existe, occupant de l'espace dans le système de fichiers.
la source
Compte tenu du contexte, je vais interpréter cette question comme:
Comment supprimer des données du disque immédiatement après leur lecture, avant la lecture du fichier complet, afin qu'il y ait suffisamment d'espace pour le fichier transformé.
La transformation peut être tout ce que vous voulez faire avec les données: compression, chiffrement, etc.
La réponse est la suivante:
En bref: lisez les données, jetez-les dans gzip (ou tout ce que vous voulez en faire), mettez en mémoire tampon la sortie afin que nous soyons sûrs de lire plus que ce que nous écrivons et de le réécrire dans le fichier. Ceci est une version plus jolie et affiche la sortie lors de l'exécution:
Je vais le parcourir ligne par ligne:
cat "$file"
lit le fichier que vous souhaitez compresser. C'est une utilisation inutile de cat (UUOC) car la partie suivante, pv, peut également lire le fichier, mais je trouve cela plus joli.Il le dirige vers des
pv
informations de progression (-cN
indique qu'il «utilise une sorte de [c] urseur» et lui donne un [N] ame).Ce canal dans
gzip
lequel fait évidemment la compression (lecture depuis stdin, sortie vers stdout).Ce tuyau dans un autre
pv
(vue tuyau).Cela entre
dd bs=$buffer iflag=fullblock
. La$buffer
variable est un nombre, quelque chose comme 50 mégaoctets. C'est cependant beaucoup de RAM que vous souhaitez consacrer à la gestion sûre de votre fichier (en tant que point de données, un tampon de 50 Mo pour un fichier de 2 Go était bien). Leiflag=fullblock
ditdd
de lire jusqu'à$buffer
octets avant de le passer. Au début, gzip écrira un en-tête, donc la sortie de gzip atterrira sur cettedd
ligne. Ildd
attendra ensuite jusqu'à ce qu'il dispose de suffisamment de données avant de les acheminer, afin que l'entrée puisse continuer à lire. De plus, si vous avez des pièces non compressibles, le fichier de sortie peut être plus gros que le fichier d'entrée. Ce tampon s'assure que, jusqu'à$buffer
octets, ce n'est pas un problème.Ensuite, nous entrons dans une autre ligne de vue de tuyau et enfin sur notre
dd
ligne de sortie . Cette ligne aof
(fichier de sortie) etconv=notrunc
spécifiée, oùnotrunc
indique dedd
ne pas tronquer (supprimer) le fichier de sortie avant d'écrire. Donc, si vous avez 500 octets deA
et que vous écrivez 3 octets deB
, le fichier seraBBBAAAAA...
(au lieu d'être remplacé parBBB
).Je n'ai pas couvert les
2>/dev/null
pièces et elles sont inutiles. Ils nettoient juste un peu la sortie en supprimantdd
le message "J'ai fini et écrit ce nombre d'octets". Les barres obliques inverses à la fin de chaque ligne (\
) font que bash traite le tout comme une grosse commande qui se connecte les unes aux autres.Voici un script complet pour une utilisation plus facile. Pour l'anecdote, je l'ai mis dans un dossier appelé «gz-in-place». J'ai alors réalisé l'acronyme que j'ai fait: GZIP: gnu zip en place. Par la présente, je présente GZIP.sh:
J'ai envie d'ajouter une autre ligne de mise en mémoire tampon avant gzip, pour l'empêcher d'écrire trop loin lorsque la
dd
ligne de mise en mémoire tampon passe à travers, mais avec seulement 50 Mo de mémoire tampon et 1900 Mo de/dev/urandom
données, cela semble fonctionner de toute façon déjà (les sommes md5 correspondent après la décompression). Rapport assez bon pour moi.Une autre amélioration serait la détection de l'écriture trop loin, mais je ne vois pas comment faire cela sans enlever la beauté de la chose et créer beaucoup de complexité. À ce stade, vous pourriez tout aussi bien en faire un programme python à part entière qui fait tout correctement (avec des échecs pour éviter la destruction des données).
la source