パイプ内に別のtarファイルを作成して、tarファイルの内容をフィルター処理するにはどうすればよいですか?


13

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

次のようなものを探しています:

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

また、このtarアーカイブの主な属性(所有権、グループ、モード、mtime)を保持することも重要です。拡張ヘッダーキーワードなどのtarファイルの他の属性はどうですか?

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

回答:


14

bsdtar(libarchiveに基づく)は、tar(および他のいくつかのアーカイブ)をstdinからstdoutにフィルターできます。たとえば、パターンに一致するファイル名のみをパススルーでき、s/old/new/名前を変更できます。bsdtarUbuntuのように、ほとんどのディストリビューション用にすでにパッケージ化されています。

sudo apt-get install bsdtar   # 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


1
すばらしい、この@original.tarアプローチがbsdtarで可能であることを知りませんでした。拡張属性と圧縮も同様に機能するようです</var/cache/pacman/pkg/libuv-1.7.0-1-x86_64.pkg.tar.xz bsdtar -czf - --include='usr/share/*' @- | tar tvz(そして、何らかの理由で空の選択が一連のゼロバイトを生成しますが、それは私にとって大きな問題ではありません)。
-Lekensteyn

1
私のテストによると、@ old.tgzを使用した古いアーカイブからのファイルでs/old/new/ は機能せず、実際のファイルでのみ機能し、ファイルシステムから直接アーカイブします。それは私にとって最も便利なユースケースになるので、本当に残念です。
バート

4

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

通常のコマンドラインツール(tarpax)は、アーカイブのメンバーを別のアーカイブにコピーすることをサポートしていません。

所有権を保持する必要がない場合は、FUSEファイルシステムを使用することをお勧めします。archivemountを使用して、アーカイブをファイルシステムとしてマウントできます。ソースアーカイブに対してこれを行い、マウントされたファイルシステムで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を持つアカウントがファイルを所有している場合、意図した結果が得られない場合があります。

Pythonのtarfileライブラリは、tarメンバーを操作するためのかなり簡単な方法を提供するため、あるtarファイルから別のtarファイルにシャッフルできます。POSIX標準形式(ustar、pax)およびいくつかのGNU拡張機能をサポートしています。以下は、標準入力でtarファイル(gzipまたはbzip2で圧縮されている可能性があります)を読み取り、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

1
bsdtar(libarchiveに基づく)は、tarアーカイブをその場でフィルタリングできます。私の答えをご覧ください。
ピーターコーデス

タスクはファームウェアイメージからデータを抽出することでしたので、所有権/グループメンバーシップは確かに重要です。ただし、Pythonのアプローチは機能します。
-Lekensteyn

0

別の特権なしのアプローチは、fakeroot所有権の変更が許可されているふりをするプログラムを使用することです。他のtar属性は失われますが、モード、mtime、およびuid / gidは保持されます。これらのコマンドは、一時ディレクトリを作成し、ファイルのサブセットを抽出して、最終的に新しいアーカイブを作成します。

mkdir tmp
<some.tar.gz \
fakeroot -- sh -c 'cd tmp && tar -xzf- subdir/ && tar -czf- subdir' |
   ssh remote@system tar -xzvf-
rm -rf tmp

0

GNUにtar--deleteオプションがあります:

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

この方法では、出力に含めないものを指定することにより、入力tarのサブセットを取得できます。

残念ながら、私は--exclude動作するオプションを得ることができなかったので、--delete最初-tに削除するものの明示的なリスト()を取得し、それを別の呼び出しに渡す必要があるようですtar

$ 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 ...

-1

私が知っていることから、tarコマンドは入力と出力の両方で tar形式を使用できません。何とかローカルでファイルを抽出し、次のような方法でtarを使用してオンザフライでtarファイルを作成する必要があります(-つまり、ファイルの代わりに標準入出力が使用されます)。

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

tar別のtarfileにtarfileを直接抽出できることは興味深いアイデアであることに注意してください...


ルートがなければ、これは明示的に保持したいすべての所有権/グループ情報を失います。
-Lekensteyn

1
質問を編集して、ホストにルートアクセス権がないことを含める必要があります。
ウリエル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.