gzファイルの最後の行を削除する

gzファイルの最後の行を削除する

解凍せずにgzファイルの最後の行を削除する必要があります。ファイルには500行があります。

どうすればいいですか?

私は試した:

 gzip -dc "$files" | tail -500 | gzip -c > "$files".tmp

しかし、うまくいきません。

答え1

解凍しないと圧縮ファイルを変更できません。

少なくとも499行目以降のすべてのテキストを削除するには、最初の499行目を解凍して499行目の終わりを見つける必要があります。行数に関係なく最後の行を削除するには、ファイル全体を解凍して最後の行が始まる場所を確認する必要があります。

ファイルが圧縮されているため、ショートカットはありません。文字エンコーディングは、以前のすべての文字によって異なります。 gzip圧縮の基本原則は、以前に見つかった文字シーケンスにはより短いビットシーケンスを使用し、まだ見つからない文字シーケンスには少し長いビットシーケンスを使用することです。文字シーケンスが繰り返されると、より小さなファイルが生成されます。前の文字をすべて確認せずに、特定の文字が改行文字であるかどうかを確認する方法はありません。

ファイルを解凍し、解凍されたストリームを処理してから、別のファイルに再度圧縮しようとすると正しいです。ファイルを切り捨てるには正しいコマンドが必要です。tail -500あなたが望むものではなく、最後の500行を維持してください。head -n 499最初の499行を保持したり、head -n -1最後の行を削除したりするために使用されます。すべてのシステムが負の引数をサポートしているわけではありませんhead。それ以外の場合は代わりに使用できますsed '$d'

gunzip <"$file" | head -n -1 | gzip >"$file".tmp
mv -- "$file".tmp "$file"

ファイルに直接書き込むことはできません。ファイルgunzip <"$file" | … | gzip >"$file"の読み込み中にファイルの上書きが開始されます。gunzipパイプラインのコマンドは並列に実行されます。一時ファイルを生成しないことは可能ですが、そうすると、コマンドが中断されるとファイルが切り捨てられる可能性があるため、良い考えではありません。したがって、これを行う方法については説明しません。

理論的には、gzip圧縮ファイルは次の方法で切り捨てることができます。

  1. 切り取る位置を決定するためにメモリから解凍します。
  2. 保持する最後の文字の後のすべてのデータを削除するには、ファイルを切り捨てます。
  3. 最後の文字を正しくエンコードするには、最後の数バイトを上書きします。
  4. 新しいファイルサイズを反映するように最初の数バイトを上書きします。

ただし、これは標準ツールを使用して行うことはできず、いくつかのカスタムプログラミングが必要であり、中断すると誤ったファイルが残ります。

答え2

例では、ストリームに解凍するのは問題ありませんが、ファイルに解凍したくないとします。できなければならない

gzip -cd "$files" | sed -e '$d' | gzip > "$files".tmp

sed最後の行に移動して削除してください。

答え3

あなたはそれを使用することができますzcat

zcat <file> | head -n <lines>

解凍するだけでラインをストリーミングするのに十分ですn

追加資料:http://www.thegeekstuff.com/2009/05/zcat-zless-zgrep-zdiff-zcmp-zmore-gzip-file-erations-on-the-compressed-files/

答え4

@Eric Renoufの回答(申し訳ありませんが、コメントが長すぎます)に基づいて、元のタイムスタンプとファイル名のメタデータをファイルに保存するには、次のようにラップします。

gzip -cd "$file" | sed -e '$d' > "$file.tmp"
touch -r "$file" "$file.tmp"
# optionally keep the old file
# mv "$files" "$file.old"
mv "$file.tmp" "$file"
gzip "$file"

または、圧縮されていないファイルがあるため、再圧縮するxz代わりにaを使用してくださいgzip。圧縮率が向上し、一般的に高速です。

関連情報