Gzip圧縮されたtar-ball圧縮されたArchive.tgz(+100ファイル、合計+ 5GB)があると仮定します。
たとえば、prefix * .jpgのような特定のファイル名パターンに一致するすべてのエントリを削除し、残りをgzip:ed tar-ballに再度保存する最も速い方法は何ですか?
古いアーカイブを置き換えるか、新しいアーカイブを作成するかは、どちらが最速でも重要ではありません。
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
が、最初のファイルがまだ読み取っていないファイルの領域を上書きしてしまう可能性がある場合)は、非常に危険です。
簡単な方法を軽視しないでください:それはあなたの目的のために十分速いかもしれません。 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
Tarに--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()
Mac OSXに付属のtarを使用すると、次のことができます。
tar -czf b.tgz --exclude '*.jpg' @a.tgz
mv b.tgz a.tgz
これを行うには、おそらくローカルディレクトリにある.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 .
@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$'
で見つけることができます。
私が使う:
tar -xvf myLarge.gz --exclude "prefix" | tar -czvf myLarge.gz -T -
この意志:
-T -
)パイプレストをtarにパイプし、myLarge.gzを再圧縮します。