Wie konvertiere ich eine .gz-Datei sicher in eine .xz-Datei?

3804
pythonic metaphor

Ich habe einige riesige Dateien, die derzeit gzippt werden und ich möchte sie xz. Ich möchte ein Skript einrichten, um dies zu tun, aber ich möchte darauf achten, dass die Daten nicht verloren gehen, dh ich sollte die gzipped-Version niemals löschen, es sei denn, die xz-Version wurde definitiv korrekt erstellt. Da es sich um große Dateien handelt, würde ich es auch vorziehen, die Datei nicht zuerst auf die Festplatte zu entpacken. Ich dachte, eine Pfeife set -o pipefail; gzip -dc file.gz | xz > file.xz && rm file.gzkönnte nahe an dem liegen, was ich will. Was ist der richtige Weg, dies zu tun? Ist dies garantiert, um Fehler zu beheben, die vor dem Entfernen der endgültigen Datei aufgetreten sind?

4
Ich denke, Sie sollten `&&` nicht `||` in Ihrer `&& rm file.gz` verwenden. Andernfalls würde mit `||` die `file.gz` entfernt, selbst wenn` xz` fehlschlägt, was Sie nicht möchten. Dan D. vor 10 Jahren 0
@ Dan D. Natürlich hast du recht, repariert pythonic metaphor vor 10 Jahren 0

1 Antwort auf die Frage

8
Horn OK Please

Durch das Hinzufügen der SHA1-Summe (die mathematisch garantiert zu einem lächerlich hohen Maß an Sicherheit führt, dass die Dateien entweder übereinstimmen, wenn die Hashwerte übereinstimmen, und die Hashwerte nicht übereinstimmen, wenn die Dateien nicht übereinstimmen), wird ein Maß an Datenintegrität hinzugefügt, um sich vor Fällen zu schützen Das Disk-Subsystem hat beim Schreiben möglicherweise einen (stillen) Fehler gemacht. Stumme Korruption ist selten, aber schleichend, wenn es passiert.

Natürlich könnten Sie immer noch verwirrende Ergebnisse haben, wenn Sie beim Lesen zufällige Fehler haben, aber in diesem Fall stimmen die Summen ohnehin nicht mit extrem hoher Sicherheit überein. Mit anderen Worten, wenn das System beschädigt ist (entweder der RAM-Speicher oder der Datenträger, der falsche Bits / umgedrehte Bits / beschädigte Daten erzeugt), wird dies fehlschlagen, wenn ein einfacher &&Vorgang erfolgreich sein könnte, und die Wahrscheinlichkeit, dass dies rmmit beschädigten Daten zur Leitung gelangt, verschwindet klein (da die meisten Fehler dazu neigen, Daten auf zufällige Weise zu beschädigen, sind die Chancen der zufälligen Änderung, die eine Hash-Kollision in SHA1 während des Rücklesens verursacht, atemberaubend klein.)

#!/bin/bash set -e set -o pipefail ORIGSUM=$(gzip -dc file.gz | tee >(xz > file.xz) | sha1sum) NEWSUM=$(unxz -c file.xz | sha1sum) if [ "$" = "$" ]; then rm file.gz; fi 

Das set -eShell-Skript wird beendet, sobald eine Zeile des Skripts einen Exit-Code ungleich Null zurückgibt.

Dann benutzen wir den teeBefehl, um die un-gzip - Ausgabe der Datei zu kopieren, sowohl den xzKompressor, und zum sha1sumProgramm. sha1sumberechnet die SHA1-Summe der im gzipped-Archiv enthaltenen Originaldaten, indem sie vorübergehend in das sha1sum-Programm entpackt wird, das die Daten liest, um die Summe zu berechnen, und verwirft die Daten. Bei der Verwendung teemüssen wir nur einmal die CPU-Kosten für das Entpacken der Datei bezahlen.

Dann führen wir einen zusätzlichen, rechenintensiven Schritt aus (für eine Super-Extra-Überprüfung), entfernen die xz-Komprimierung der Datei (vorübergehend in einen Stream) und leiten sie an sha1sum, um unsere SHA1-Summe "new file" zu erhalten.

Dann vergleichen wir die beiden Summen, und wenn sie nicht gleich sind, oder wenn eine oder beide eine Länge von Null haben, wird entweder ein Skriptfehler ausgegeben (der dank set -e) endet, oder die Datei wird nicht angezeigt entfernt. elseWenn Sie möchten, können Sie eine Klausel für die benutzerfreundliche Fehlerbehandlung implementieren. Dieses grundlegende Skript ist jedoch äußerst sicher, auch wenn es für Benutzer, die den Befehl interaktiv ausführen, nicht sehr informativ ist.

Am Ende wird die file.gzVerknüpfung nur dann aufgehoben, wenn die unkomprimierten Inhalte von file.gzund file.xzzu dem Zeitpunkt, zu dem die Hashes berechnet wurden, exakt identisch sind, mit einem astronomisch hohen Maß an Sicherheit (die Wahrscheinlichkeit, dass etwas Schlimmes schief geht, wäre etwas wie 1 in 1 mit 300 Nullen danach). An diesem Punkt müssen Sie sich nur darum kümmern, dass die Daten beschädigt werden, nachdem das Skript beendet wurde. ;)


Performance

Dieses Skript wird mit der gleichen Geschwindigkeit wie das ursprüngliche Skript in der Frage ausgeführt, mit Ausnahme des Teils, der ausgeführt wird unxz. Zum Glück ist das Dekomprimieren von LZMA extrem schnell, fast so schnell wie das normale Zip und so etwas um eine Größenordnung schneller als das Komprimieren in LZMA. Wenn Sie über eine schnelle CPU verfügen und die Dateien ausreichend klein sind, sollte dies nicht zu einer längeren Laufzeit des Skripts führen. Wenn Sie jedoch Wert auf die Integrität der Daten über die Leistung legen, ist dies ein klarer Gewinn.


Gutschrift bei fälliger Gutschrift

Diese Antwort auf StackOverflow hat mir beim Schreiben dieses Skripts wesentlich geholfen .

Dies ist eine sehr gute Möglichkeit, um sicherzustellen, dass die Komprimierung korrekt funktioniert und die Laufzeit ungefähr gleich bleibt. Und ja, ich habe einige dieser Operationen zeitlich festgelegt, und der xz-Schritt war um eine Größenordnung langsamer als der unxz-Schritt, also bin ich nicht besorgt über diesen Teil. pythonic metaphor vor 10 Jahren 0
Ich sollte hinzufügen, dass auf einem System mit ECC-RAM und einem Dateisystem mit integrierten Integritätsprüfungen wie "btrfs" oder "zfs" das Betriebssystem und die Hardware * bereits * zusammenarbeiten, um etwas Ähnliches zu tun wie ich sha1sum test. Wenn Sie also in einer solchen Konfiguration arbeiten, ist das Risiko, dass Sie die sha1sum-Prüfung aus diesem Skript entfernen, ziemlich vernachlässigbar. Wenn Sie jedoch über ein nicht ECC-RAM und ein Dateisystem verfügen, das keine integrierte Integrität aufweist, wird Ihr Skript * erheblich * sicherer *. Horn OK Please vor 10 Jahren 0