web-dev-qa-db-ja.com

1つのコマンドで複数のtarファイルを連結する

毎日4〜100個の非常に大きなtar(〜20GB)アーカイブファイルを受け取ります。私は過去に、ファイルシステムに表示される各アーカイブをループして、次のようなことを行って、それらを連結しています。

/bin/tar -concatenate --file=allTars.tar receivedTar.tar

ただし、これに伴う問題は、tarファイルをどんどん連結するので、allTars.tarの最後まで読み取って、再度連結を開始する必要があることです。別のtarファイルの追加を開始するのに20分以上かかる場合があります。それは遅すぎて、完全なallTars.tarの合意された納期がありません。

私もtarコマンドに次のようなファイルのリストを渡そうとしました:

/bin/tar --concatenate --file=alltars.tar receiverTar1.tar receivedTar2.tar receivedTar3.tar...etc

これは非常に奇妙な結果をもたらしました。 allTars.tarは予想されるサイズ(つまり、すべてのreceivedTar.tarファイルのサイズを合計したものに近い)ですが、allTars.tarが解凍されたときにファイルを上書きするようです。

これらのすべてのtarファイルを1つのコマンドで連結する方法はありますか。そのため、毎回連結されるアーカイブの最後まで読み取る必要はありませんおよびすべてのファイル/データで正しくアンパックします?

6
Jeff Hall

これは役に立たないかもしれませんが、-iオプションは、最終的なアーカイブから抽出するときに、タールを一緒にcatするだけです。 tarファイルは、ヌルでいっぱいのヘッダーと、レコードの終わりまでのヌルパディングで終了します。 --concatenate tarは、最終的なヘッダーの正確な位置を見つけるためにすべてのヘッダーを調べ、そこから上書きを開始する必要があります。

タールをcatだけにすると、ヘッダー間に余分なヌルができます。 -iオプションは、ヘッダー間のこれらのヌルを無視するようにtarに要求します。だからあなたはできる

cat  receiverTar1.tar receivedTar2.tar ... >>alltars.tar
tar -itvf alltars.tar

また、あなたのtar --concatenate例が機能するはずです。ただし、複数のtarアーカイブに同じ名前のファイルがある場合、結果のtarからすべてを抽出するときに、そのファイルを数回書き換えます。

7
meuh

この質問はかなり古いですが、次の情報をもっと早く見つけられるようになればよかったと思います。他の誰かがこれに遭遇した場合は、お楽しみください:

Jeffが上記で説明しているのは、gnu tarの既知のバグです(2008年8月に報告)。最初のアーカイブ(-fオプションの後のアーカイブ)のみがEOFマーカーが削除されます。3つ以上のアーカイブを連結しようとすると、最後のアーカイブが非表示になります"ファイルエンドマーカーの後ろ。

Tarのバグです。末尾のゼロブロックを含むアーカイブ全体を連結するため、デフォルトでは、結果のアーカイブの読み取りは最初の連結後に停止します。

出典: https://lists.gnu.org/archive/html/bug-tar/2008-08/msg00002.html(およびそれに続くメッセージ)

バグの年数を考えると、修正されるかどうかは疑問です。影響を受けるクリティカルマスがあるとは思えません。

このバグを回避する最良の方法は、少なくともファイルシステム上の.tarファイルに対して-iオプションを使用することです。

Jeffが指摘するように、tar --concatenateは、次のアーカイブを連結する前にEOFに到達するまでに長い時間がかかる可能性があります。したがって、 untarするにはtar -iオプションが必要です。以下をお勧めします。

を使用する代わりにtar --concatenate -f archive1.tar archive2.tar archive3.tar実行する方が良いでしょうテープデバイスに書き込む場合は、cat archive2.tar archive3.tar >> archive1.tarまたはddにパイプします。また、このcouldは、新しいデータをテープに(過剰に)書き込む前にテープがゼロにならなかった場合、予期しない動作を引き起こすことに注意してください。そのため、私のアプリケーションで採用するアプローチは、質問の下のコメントで提案されているように、ネストされたtarです。

上記の提案は、次の非常に小さなサンプルベンチマークに基づいています。

time tar --concatenate -vf buffer.100025.tar buffer.100026.tar
  real  65m33.524s
  user  0m7.324s
  sys   2m50.399s

time cat buffer.100027.tar >> buffer.100028.tar
  real  46m34.101s
  user  0m0.853s
  sys   1m46.133s

Buffer。*。tarファイルのサイズはすべて100GBであり、システムは各呼び出しを除いてほとんどアイドル状態でした。時間差は非常に大きいため、サンプルサイズが小さいにもかかわらず、このベンチマークは有効であると個人的に考えていますが、これについては自由に判断でき、おそらくこのようなベンチマークをハードウェアで実行するのが最善です。

9
trs

これは1行のコマンドではありませんが、/ usr/local/bin/tar_mergerにファイルを作成して実行可能にできる場合は、このpython3スクリプトを使用してtarをマージしてください。

マージしたいtarを最終的なファイルの名前のフォルダーに入れて、

tar_merger folder

フォルダー名で出力tarを作成し、フォルダー内のすべてのtarを調べて、ファイルを新しいtarに追加します。私にとっては、何千もの約1 GBのタールをマージすることで問題なく動作します。

#!/bin/env python3
# Merges many tars into a single one
# Wolfang Torres - [email protected]

from pathlib import Path
from tarfile import TarFile
from sys import argv


def cli(folder):
    """Merges all the tars in folder to a single tar"""
    folder = Path(folder)
    tar_path = folder.parent / f"{folder.name}.tar"
    n = 0
    sub_tars = Tuple(folder.glob("*.tar"))
    total = len(sub_tars)
    with TarFile(tar_path, "w", encoding="utf-8") as tar:
        for sub_path in sub_tars:
            n += 1
            print(f"Adding tar {n}/{total} {sub_path.name}")
            with TarFile(sub_path, "r", encoding="utf-8") as sub_tar:
                for file in sub_tar:
                    data = sub_tar.extractfile(file)
                    tar.addfile(file, data)
    print(f"Finished merging {n} Tars into {tar_path}")


if __name__ == "__main__":
    if len(argv) < 2 or argv[1] in ("-h", "--help"):
        print(f"{argv[0]} folder")
        print()
        print("Merges all the tars inside of `folder` to `folder.tar`")
    else:
        cli(argv[1])
0
Wolfang Torres

すでに述べたように、ターゲットアーカイブファイルは、2番目のソースアーカイブが追加される前に最後まで読み取る必要があります。 GNU tarには-nオプションは、ファイルがシーク可能であると想定するように指示します(tarはシークできないテープおよびストリームアーカイブ用に設計されていたことを思い出してください)。 GNU tarはおそらくファイルがシーク可能かどうかを自動検出するようにデフォルト設定されていますが、あなたなどの多くのユーザーは、-nオプション:

tar -n --concatenate --file=target_file.tar  other_file.tar

(執筆の時点で)tarのどのバージョンがこのコマンドで期待どおりに動作するかを確認できません。他のユーザーがこのソリューションを証明する能力を持っている場合は、以下にコメントしてください。この回答を適宜更新します。

0
Micah W