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

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

私は毎日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 つのコマンドで連結する方法はありますか。そうすれば、連結するアーカイブの最後まで毎回読み取る必要がなくなります。そしてすべてのファイル/データが正しく解凍されていますか?

答え1

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

tarだけの場合cat、ヘッダー間に余分なヌルが残ります。この-iオプションは、ヘッダー間のヌルを無視するようにtarに指示します。そのため、

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

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

答え2

この質問はかなり古いものですが、次の情報をもっと早く見つけられればよかったと思います。もし他の誰かがこれに出会ったら、楽しんでください:

Jeff が上で説明しているのは、gnu tar の既知のバグです (2008 年 8 月に報告)。最初のアーカイブ (オプションの後のアーカイブ-f) のみ、EOF マーカーが削除されます。2 つ以上のアーカイブを連結しようとすると、最後のアーカイブはファイル終了マーカーの背後に「隠され」ます。

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

ソース:https://lists.gnu.org/archive/html/bug-tar/2008-08/msg00002.html (および次のメッセージ)

バグの発生年数を考えると、修正されるかどうか疑問です。影響を受ける重大な部分があるとは思えません。

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

Jeff が指摘しているように、tar --concatenate次のアーカイブを連結する前に EOF に到達するまでに長い時間がかかることがあります。したがって、解凍オプションが必要な「壊れた」アーカイブに困っている場合はtar -i、次の方法をお勧めします。

代わりに tar --concatenate -f archive1.tar archive2.tar archive3.tar おそらく逃げた方が良いだろう cat archive2.tar archive3.tar >> archive1.tarddまたは、テープデバイスに書き込む場合はパイプを使用します。また、このできた新しいデータを(上書き)書き込む前にテープがゼロ化されていない場合、予期しない動作が発生します。そのため、質問の下のコメントで提案されているように、アプリケーションで採用するアプローチはネストされた 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 ファイルはすべて 100 GB のサイズで、システムは各呼び出しを除いてほぼアイドル状態でした。時間差は十分に大きいため、サンプル サイズが小さいにもかかわらず、個人的にはこのベンチマークは有効であると考えていますが、これについてはご自身の判断でかまいません。おそらく、このようなベンチマークを自分のハードウェアで実行するのが最善でしょう。

答え3

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

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

このコマンドで期待どおりに動作する tar のバージョンがあるかどうかは、執筆時点では確認できません。他のユーザーがこの解決策を証明できる場合は、以下にコメントしてください。それに応じてこの回答を更新します。

答え4

連結は I/O を集中的に使用するため、RAID 0 で 3 つの SSD (1 TB) を使用することをお勧めします。SATA 3 の 1 つの SSD では、読み取り速度が 500 MB/秒、書き込み速度も同程度になります。確かに高価ですが、3 倍の速さです。

関連情報