Angenommen, ich habe eine Datei mit 80 GB /root/bigfile
auf einem 100-GB-System und möchte diese Datei in einem Archiv ablegen /root/bigarchive.tar
Ich muss diese Datei natürlich gleichzeitig mit dem Hinzufügen im Archiv löschen. Daher meine Frage:
Wie lösche ich eine Datei gleichzeitig mit dem Hinzufügen in einem Archiv?
tar
zip
compression
gzip
user123456
quelle
quelle
Ein unkomprimiertes Teerarchiv einer einzelnen Datei besteht aus einem Header, der Datei und einem Trailing Pad. Ihr Hauptproblem besteht also darin, dem Anfang Ihrer Datei 512 Byte Header hinzuzufügen. Sie können beginnen, indem Sie das gewünschte Ergebnis nur mit der Kopfzeile erstellen:
Kopieren Sie dann die ersten 10G Ihrer Datei. Der Einfachheit halber gehen wir davon aus, dass Ihr dd jeweils 1Gib lesen / schreiben kann:
Wir geben jetzt die kopierten Daten aus der Originaldatei frei:
Dies ersetzt die Daten durch spärliche Nullen, die keinen Platz im Dateisystem beanspruchen. Fahren Sie auf diese Weise fort, indem Sie a
skip=10
zum nächsten hinzufügendd
und dann denfallocate
Startversatz auf erhöhen-o 10GiB
. Fügen Sie ganz am Ende einige Nullzeichen hinzu, um die endgültige TAR-Datei auszufüllen.Wenn Ihr Dateisystem dies nicht unterstützt
fallocate
, können Sie etwas Ähnliches tun, jedoch am Ende der Datei beginnen. Kopieren Sie zuerst die letzten 10 Gibytes der Datei in eine Zwischendatei mit dem Namen zpart8
. Verwenden Sie dann dentruncate
Befehl, um die Größe der Originaldatei zu verringern. Gehen Sie ähnlich vor, bis Sie 8 Dateien mit jeweils 10Gibyte haben. Sie können dann den Header verketten undpart1
anbigarchive.tar
, dann entfernenpart1
und dann verkettenpart2
und entfernen und so weiter.quelle
Das Löschen einer Datei macht nicht unbedingt das, was Sie denken. Deshalb wird in UNIX-ähnlichen Systemen der Systemaufruf aufgerufen
unlink
und nichtdelete
. Von der Handbuchseite:Infolgedessen bleibt diese Datei vorhanden, solange der Datenkompressor / Archivierer aus der Datei liest, und belegt Speicherplatz im Dateisystem.
quelle
In Anbetracht des Kontextes werde ich diese Frage wie folgt interpretieren:
So entfernen Sie Daten unmittelbar nach dem Lesen von der Festplatte, bevor die vollständige Datei gelesen wurde, damit genügend Speicherplatz für die transformierte Datei vorhanden ist.
Die Umwandlung kann alles sein, was Sie mit den Daten tun möchten: Komprimieren, Verschlüsseln usw.
Die Antwort lautet:
Kurz gesagt: Lesen Sie Daten, werfen Sie sie in gzip (oder was auch immer Sie damit machen möchten), puffern Sie die Ausgabe, damit wir sicher mehr lesen als schreiben, und schreiben Sie sie zurück in die Datei. Dies ist eine schönere Version, die die Ausgabe während des Betriebs zeigt:
Ich werde es Zeile für Zeile durchgehen:
cat "$file"
liest die Datei, die Sie komprimieren möchten. Es ist eine nutzlose Verwendung von cat (UUOC), da der nächste Teil, pv, die Datei ebenfalls lesen kann, aber ich finde das hübscher.Es leitet es weiter, in
pv
das Fortschrittsinformationen-cN
angezeigt werden ( sagt, dass es eine Art [c] ursor verwendet und ihm eine [N] ame gibt).Die Pipes, in
gzip
die offensichtlich die Komprimierung erfolgt (Lesen von stdin, Ausgeben an stdout).Das leitet in ein anderes
pv
(Rohransicht).Das pfeift hinein
dd bs=$buffer iflag=fullblock
. Die$buffer
Variable ist eine Zahl, ungefähr 50 Megabyte. Es ist jedoch viel RAM, das Sie für die sichere Handhabung Ihrer Datei verwenden möchten (als Datenpunkt waren 50 MB Puffer für eine 2-GB-Datei in Ordnung). Dasiflag=fullblock
sagtdd
, dass bis zu$buffer
Bytes gelesen werden sollen, bevor es durchgeleitet wird. Zu Beginn schreibt gzip einen Header, sodass die Ausgabe von gzip in dieserdd
Zeile landet . Danndd
warten , bis es genügend Daten hat , bevor es durch Rohrleitungen, so dass die Eingabe weiter lesen kann. Wenn Sie nicht komprimierbare Teile haben, ist die Ausgabedatei möglicherweise größer als die Eingabedatei. Dieser Puffer stellt sicher, dass dies bis zu$buffer
Bytes kein Problem ist.Dann gehen wir in eine andere Pipe-View-Linie und schließlich auf unsere Ausgangslinie
dd
. Diese Zeile hatof
(Ausgabedatei) undconv=notrunc
angegeben, wobei angegeben wird,notrunc
dassdd
die Ausgabedatei vor dem Schreiben nicht abgeschnitten (gelöscht) werden soll. Wenn Sie also 500 Bytes habenA
und Sie schreiben 3 ByteB
, wird die Datei seinBBBAAAAA...
(anstatt werden ersetzt durchBBB
).Ich habe die
2>/dev/null
Teile nicht abgedeckt und sie sind unnötig. Sie räumen die Ausgabe nur ein wenig auf, indem sie diedd
Meldung "Ich bin fertig und habe so viele Bytes geschrieben" unterdrücken . Die Backslashes am Ende jeder Zeile (\
) lassen bash das Ganze als einen großen Befehl behandeln, der ineinander geleitet wird.Hier ist ein vollständiges Skript zur einfacheren Verwendung. Anekdotisch habe ich es in einen Ordner namens "gz-in-place" gelegt. Dann erkannte ich das Akronym, das ich gemacht hatte: GZIP: gnu zip in-place. Hiermit präsentiere ich GZIP.sh:
Ich möchte vor gzip eine weitere Pufferzeile hinzufügen , um zu verhindern, dass sie
dd
beim Durchlaufen der Pufferzeile zu weit schreibt , aber mit nur 50 MB Puffer und 1900 MB/dev/urandom
Daten scheint sie ohnehin schon zu funktionieren (die MD5-Summen stimmen nach dem Dekomprimieren überein). Gut genug Verhältnis für mich.Eine weitere Verbesserung wäre die Erkennung von zu weitem Schreiben, aber ich sehe nicht, wie ich das tun kann, ohne die Schönheit der Sache zu entfernen und viel Komplexität zu schaffen. An diesem Punkt können Sie es genauso gut zu einem vollwertigen Python-Programm machen, das alles richtig macht (mit Failafes, um Datenvernichtung zu verhindern).
quelle