大きな.tgzからファイルを効率的に削除します


14

gzip圧縮されたtar-ball compressArchive.tgz(+100ファイル、合計+ 5gb)があると仮定します。

たとえば、prefix * .jpgなどの特定のファイル名パターンに一致するすべてのエントリを削除し、gzip:ed tar-ballに残りを保存する最も速い方法は何ですか?

古いアーカイブを置き換えるか、新しいアーカイブを作成するかは重要ではありません。


回答:


14

GNU tarでは、次のことができます。

pigz -d < file.tgz |
  tar --delete --wildcards -f - '*/prefix*.jpg' |
  pigz > newfile.tgz

bsdtar

pigz -d < file.tgz |
  bsdtar -cf - --exclude='*/prefix*.jpg' @- |
  pigz > newfile.tgz

pigzのマルチスレッドバージョンですgzip)。

次のようにファイルを上書きできます:

{ pigz -d < file.tgz |
    tar --delete --wildcards -f - '*/prefix*.jpg' |
    pigz &&
    perl -e 'truncate STDOUT, tell STDOUT'
} 1<> file.tgz

しかし、結果が元のファイルよりも圧縮されていない場合は特に危険です(この場合、2番目pigzのファイルは最初のファイルがまだ読み取っていないファイルの領域を上書きする可能性があります)。


答えてくれてありがとう。来週ベンチマークを実行して、どれが私のアーカイブとシステムのパフォーマンスを向上させるかを確認し、それを受け入れます。
アクセルウィルガート

8

簡単な方法を軽視しないでください:それはあなたの目的のために十分に速いかもしれません。AVFSディレクトリとしてアーカイブにアクセスするには:

cd ~/.avfs/path/to/original.tar.gz\#
pax -w -s '/^.*\.jpg$//' | gzip >/path/to/filtered.tar.gz        # POSIX
tar -czf /path/to/filtered.tar.gz -s '/^.*\.jpg$//' .            # BSD
tar -czf /path/to/filtered.tar.gz --transform '/^.*\.jpg$//' .   # GNU

より原始的なツールでは、最初にファイルを除くファイルを抽出し.jpg、次に新しいアーカイブを作成します。

mkdir tmpdir && cd tmpdir
<original.tar.gz gzip -d | pax -r -pe -s '/^.*\.jpg$//'
pax -w . | gzip >filtered.tar.gz
cd .. && rm -rf tmpdir

あなたのタールが持っている場合--exclude

mkdir tmpdir && cd tmpdir
tar -xzf original.tar.gz --exclude='*.jpg'
tar -czf filtered.tar.gz .
cd .. && rm -rf tmpdir

ただし、rootとして実行しないと、ファイルの所有権とモードが破壊される可能性があります。最良の結果を得るには、高速ファイルシステムの一時ディレクトリを使用してください。十分な大きさの一時ディレクトリがある場合は、tmpfsを使用してください。

パススルーとして機能するアーカイバのサポート(つまり、アーカイブの読み取りとアーカイブの書き込み)は制限される傾向があります。GNU tarはアーカイブからメンバーを削除することができ--delete、操作オプション(「--deleteときのオプションが正しく動作することが報告されているtarから、フィルタとして機能stdinするstdout。」)、それはおそらくあなたの最良の選択肢です。

数行のPythonで強力なアーカイブフィルターを作成できます。そのtarfileライブラリは、シークできないストリームからの読み取りと書き込みが可能で、Pythonの任意のコードを使用して、フィルタリング、名前変更、変更を行うことができます…

#!/usr/bin/python
import re, sys, tarfile
source = tarfile.open(fileobj=sys.stdin, mode='r|*')
dest = tarfile.open(fileobj=sys.stdout, mode='w|gz')
for member in source:
    if not (member.isreg() and re.match(r'.*\.jpg\Z', member.name)):
        sys.stderr.write(member.name + '\n')
        dest.addfile(member, source.extractfile(member))
dest.close()

また、rootとして実行すると、tarファイルが最初に作成されたものと同じuid <=>ユーザー名マッピングを持つマシンで実行されない限り、uid / usernamesを破壊します。ACL、拡張属性も影響を受ける可能性があります。を使用tarすると、pオプションを追加できます。
ステファンシャゼル

2

Mac OSXに付属のtarを使用すると、次のことができます。

tar -czf b.tgz --exclude '*.jpg' @a.tgz
mv b.tgz a.tgz

1

これを行うには、おそらくローカルディレクトリにある.tgzファイルのすべての内容を抽出し、不要なファイルを消去してから.tgzを再圧縮する必要があります。

それは長く、十分な空きディスク容量が必要ですが、私の知る限り、他に方法はありません。

/tmpdir/withalotofspace十分な空き領域があるようなパスが既にある場合(を使用して確認してください df -h /tmpdir/withalotofspace)、次のようなことができます。

$ cd /tmpdir/withalotofspace
$ tar -xvfz /path/to/compressedArchive.tgz
$ find /tmpdir/withalotofspace/ -type f -iname '*.jpg' -delete
$ tar -cvzf /path/to/purgedcompressedArchive.tgz .

他の回答が示すように、配管を通じて任意の時点で、ディスク上の非圧縮データを格納する必要はありません
トビアスKienzler

0

@Gillesの回答が気に入っていますが、さらに簡略化できる点が異なります。解凍後、たとえばgunzip foo.tgz、ファイルはになりfoo.tar、ファイルはで削除できますtar -f foo.tar --delete file|directory。以下は、tarファイルからディレクトリを削除する例です。

    phablet@ubuntu-phablet:~/Downloads$ tar -cvf moo.tar moo1/
    moo1/
    moo1/moo2/
    moo1/moo2/moo3/
    moo1/moo2/moo3/moo4/
    moo1/moo2/moo3/moo4/moo5/
    phablet@ubuntu-phablet:~/Downloads$ tar -tf moo.tar 
    moo1/
    moo1/moo2/
    moo1/moo2/moo3/
    moo1/moo2/moo3/moo4/
    moo1/moo2/moo3/moo4/moo5/
    phablet@ubuntu-phablet:~/Downloads$ tar -f moo.tar --delete "moo1/moo2/moo3"
    phablet@ubuntu-phablet:~/Downloads$ tar -tf moo.tar 
    moo1/
    moo1/moo2/

特定のファイルタイプはで見つけることができますtar -tf foo.tar|egrep -i '.jpg$'

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.