パイプラインから別のtarファイルを生成するためにtarファイルの内容をフィルタリングする方法は?

パイプラインから別のtarファイルを生成するためにtarファイルの内容をフィルタリングする方法は?

権限、mtimesなど、保存したいさまざまな属性を持ついくつかのディレクトリを含む外部システムの単一のtarファイルを考えてみましょう。通常のユーザー(ルートではなく)としてこれらのファイルのサブセットを簡単に取得する方法は?

似たようなものを探しています。

tar -f some.tar.gz --subset subdir/ | ssh remote@system tar xvz

このtarアーカイブで主な属性(所有権、グループ、モード、mtime)を保存することも重要です。 tarファイルの他の属性(例:タイトルキーワードの拡張

そのサブディレクトリに大容量ファイルが含まれている場合、一時ディレクトリの使用を回避するソリューションのボーナスポイント。

答え1

bsdtar(libarchiveベース)標準入力から標準出力にtar(および他のいくつかのアーカイブ)をフィルタリングできます。例えば、一致するファイル名のみを渡すパターンで、s/old/new/名前を変更できます。 Ubuntuのようなほとんどのディストリビューションはすでにパッケージ化されています。bsdtar libarchive-tools

sudo apt-get install libarchive-tools   # or aptitude, if you have it.

# example from the man page:
bsdtar -c -f new.tar --include='*foo*' @old.tgz
#create new.tar containing only entries from old.tgz containing the string ‘foo’
bsdtar -czf - --include='*foo*' @-  # filter stdin to stdout, with gzip compression of output.

入力/出力用に選択できる圧縮形式がいくつかあるため、gunzip / lz4を介して手動でパイプする必要はありません。-stdinを使用する@tarfileか、-通常どおりstdoutを使用する構文を使用できます。


私の検索でもこのストリーミングtar修正ツールが登場しましたが、JavaScriptを使用して必要なアーカイブ変更を定義したいと思います。 (すべてがjsで書かれているようです。)

https://github.com/mafintosh/tar-stream

答え2

最も簡単な方法は、アーカイブ全体をコピーすることです。大きすぎるのでそうしたくないでしょう。

一般的なコマンドラインツール(tar、、pax)は、あるアーカイブのメンバーを別のアーカイブにコピーすることをサポートしていません。

所有権を維持する必要がない場合は、以下を使用することをお勧めします。ヒューズファイルシステムあなたはそれを使用することができますアーカイブマウントアーカイブをファイルシステムとしてマウントします。ソースアーカイブでこれを行い、マウントされたファイルシステムでtarを実行します。

archivemount some.tar.gz mnt
cd mnt
tar -cz subdir | ssh example.com tar -xz
fusermount -u mnt

または、次のものを使用できます。AVFS:

mountavfs
cd ~/.avfs$PWD/some.tar.gz\#
tar -cz subdir | ssh example.com tar -xz

または、tar元のアーカイブで実行し、以下を介してリモートシステムに抽出することもできます。SSHFS

sshfs example.com: mnt
cd mnt
tar -xf /path/to/some.tar.gz subdir
fusermount -u mnt

ただし、所有権を維持する必要がある場合、これらの方法はすべて面倒です。すべてローカルコンピュータからファイルに抽出することが含まれるため、ファイルの所有権は期待どおりにする必要があります。離れて所有権。この操作はrootとして実行する必要があり、ローカルシステムとリモートホスト間で名前またはIDが異なるアカウントがファイルを所有している場合は、予期した結果を提供できない可能性があります。

Pythontarfileライブラリは、tarメンバーを操作してあるtarファイルから別のtarファイルに移動するための非常に簡単な方法を提供します。 POSIX標準フォーマット(ustar、pax)といくつかのGNU拡張機能をサポートしています。これは、標準入力(gzipまたはbzip2圧縮可能)からtarファイルを読み取り、標準出力にbzip2圧縮tarファイルを書き込むテストされていないPythonスクリプトです。ソースのメンバーがスクリプトに渡されたパラメーターで始まる場合、そのメンバーはコピーされます。

#!/usr/bin/env python2
import sys, tarfile
source = tarfile.open(fileobj=sys.stdin)
destination = tarfile.open(fileobj=sys.stdout, mode='w:bz2')
for info in source:
    if info.name.startswith(sys.argv[1]):
        destination.addfile(info)
destination.close()

次のように呼ばれる。

tar_filter <some.tar.gz subdir/ | ssh example.com tar -xj

答え3

GNUには次のオプションがtarあります--delete

$ tar -c a b c | tar --delete a | tar -t
b
c

このようにして、何を指定して入力tarのサブセットを取得できます。いいえ出力に含まれます。

--exclude残念ながら、使用されているオプションを取得できないため、最初に削除する項目の明示的なリスト()を--delete取得してから、別の呼び出しに渡す必要があるようです。-ttar

$ tar --delete --no-recursion `tar -t --exclude subdir <some.tar` <some.tar | ssh ...

あるいは、リストが長すぎるか複雑な場合は、リストを外部ファイルに保存できます。

$ tar -t --exclude subdir <some.tar >to_delete.lst
$ tar --delete --no-recursion -T to_delete.lst <some.tar | ssh ...

答え4

私が知っている限り、このtarコマンドはtar形式では使用できません。両方入力と出力で。どういうわけかローカルからファイルを抽出し、tarを再利用して次のようにtarファイルを動的に生成する必要があります(これは-ファイルの代わりに標準入力/出力を使用することを意味します)。

tar cf - subdir/ | ssh remote@system 'cd extractdir && tar xvf -'

他のtarファイル内から直接tarファイルを直接抽出できることはtar興味深いアイデアです。

関連情報