web-dev-qa-db-ja.com

.gzファイルを.xzファイルに安全に変換するにはどうすればよいですか

現在gzipで圧縮されている巨大なファイルがいくつかあり、それらをxzしたいと思います。これを行うためのスクリプトを設定したいのですが、データが失われないように注意したいのです。つまり、xzバージョンが確実に正しく作成されていない限り、gzip圧縮されたバージョンを削除しないでください。これらは大きなファイルなので、最初にファイルをディスクに解凍しないこともお勧めします。私はパイプを考えていましたset -o pipefail; gzip -dc file.gz | xz > file.xz && rm file.gz私が望むものに近いかもしれません。これを行う正しい方法は何ですか?これは、最終ファイルを削除する前に発生した障害をキャッチすることが保証されていますか?

5

SHA1合計を追加すると(ハッシュが一致するとファイルが一致し、ファイルが一致しない場合はハッシュが一致しないことが数学的に非常に高い確実性が保証されます)、データの整合性の尺度が追加され、ディスクサブシステムが書き込み中に(サイレント)ミスを犯した可能性があります。サイレント破損はまれですが、発生すると潜行します。

もちろん、読み取り中にランダムなエラーが発生した場合、結果が混乱する可能性がありますが、その場合、合計は非常に高い確実性でとにかく一致しません。言い換えると、システムが破損している場合(RAMまたはディスクが間違ったビット/反転ビット/破損したデータを生成している)の場合)、これは失敗し、単純な&&が成功する可能性があります。破損したデータでrm行に到達することは、vanishingly小さいです(ほとんどのエラーはランダムな方法でデータを破損する傾向があるため、ランダムな変更が原因で発生する可能性がありますリードバック中のSHA1でのハッシュの衝突は、息を呑むほど小さいものです。)

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

set -eは、スクリプトのany行がゼロ以外の終了コードを返すとすぐにシェルスクリプトを終了させます。

次に、teeコマンドを使用して、gzip圧縮されていないファイルの出力をbothxzコンプレッサー、andsha1sumにコピーします。プログラム。 sha1sumは、gzip圧縮されたアーカイブに含まれる元のデータのSHA1合計を、sha1sumプログラムに一時的に解凍して計算します。このプログラムは、データを読み取って合計を計算し、データを破棄します。 teeを使用することで、ファイルを解凍するためのCPUコストを1回支払うだけで済みます。

次に、追加の計算コストのかかる手順(超追加検証用)を実行し、ファイルのxz圧縮を(一時的にストリームに)削除し、sha1sumにパイプして、「新しいファイル」のSHA1合計を取得します。

次に、2つの合計を比較し、それらが等しい文字列でない場合、またはそれらの一方または両方が長さがゼロの場合、スクリプトエラー(set -eのおかげで終了します)が発生するか、ファイルが終了しません除去される。必要に応じて、ユーザーフレンドリーなエラー処理のためにelse句を実装できますが、この重要なスクリプトはそのままでも非常に安全ですが、コマンドを対話的に実行するユーザーにはあまり有益ではありません。

結局、file.gzはリンク解除されるだけですif and only iffile.gzfile.xzの非圧縮コンテンツは、ハッシュが計算された時点で完全に同一です。天文学的に高い確実性(何か悪いことがうまくいかない確率は、1分の1のようなもので、その後に300個のゼロがあります)。その時点で、データが破損することだけを心配する必要がありますafterこのスクリプトは終了します。 ;)


パフォーマンス

このスクリプトは、質問の元のスクリプトとほぼ同じ速度で実行されます。unxzを実行する部分ではexceptionです。幸い、LZMAからの解凍は非常に高速で、通常のZipとほぼ同じ速度であり、compressing toLZMAよりも1桁高速です。 CPUが高速で、ファイルが十分に小さい場合、スクリプトにtooランタイムを追加する必要はありませんが、パフォーマンスよりもデータの整合性を重視する場合は、明確な勝利。


クレジットが必要なクレジット

StackOverflowでのこの回答 このスクリプトを書くのに大いに役立ちました。

9
allquixotic