機械学習をやろうとしたらデータクレンジングに明け暮れていた件(2) ~大量のファイルを分割アーカイブする~

技研のまつけんです。

前回の記事では、複数のアーカイブを展開してファイルやフォルダの名前の傾向を調べる過程を紹介しました。今回は、その逆の「多数のファイルを分活してアーカイブする」ためのシェルスクリプトを紹介したいと思います (前回の「まとめ」では違う予告をしましたが、その前に今回の作業をする機会があったので、先に記事にしました)。

自分がデータクレンジングしたものを誰かに渡すことがあります。その際、メールで送るにしてもサーバに置くにしても、再びアーカイブ (+圧縮) すると便利なのですが、数ギガバイトのzipやtgzだと色々と不便です。そこで、分割してアーカイブしたくなります。それを実現するのに、真っ先に思いつく方法は、a、b、cという3つのフォルダがあるのであれば (そして、3つのフォルダ内のデータ量に偏りが無いのであれば)、

のように

  • aで始まるものは、a.tgz
  • bで始まるものは、b.tgz
  • cで始まるものは、c.tgz

としてしまうことでしょう。

しかしながら、いつもこのように綺麗に分かれているとは限りません。そうすると、どのように分ければ良いか検討しなければなりません。これを手作業でするとなると意外に面倒です。そこで、今回は、最終的なアーカイブファイルの個数の上限を指定すると、分け方を考えてくれるスクリプトを作りました。こちらです:

今回のような処理を自動で行おうと考えた場合、もっとも簡単な方法は「先頭から何文字までを共通として扱えば目的を達成できるか」を調べることでしょう。例えば、前回の記事で扱った例とよく似たフォルダ構成:

のような場合、「data_000/20*」は上記の全ての項目を指しますが、先頭の12文字「data_000/201」までを共通として扱い、13文字目の違いを利用して

とすれば、3つのファイルにわけてアーカイブすることが出来ます。13文字目までを共通として扱い、14文字目の違いを利用して

とすれば、4つに分かれます。

こちらに対して実行した結果です。そのときの実行中の画面表示がこちらです:

最初の部分は、何文字目まで共通にすると幾つのファイルが出来るか、のリストです。冒頭で、LIM=10としているので、10ファイル以下におさまる最大の値として、「25文字目まで共通」が選ばれています。実行中のステータスの表示などについては、カーソルを移動 [1][2] して上書きすることで実現しています。途中でctrl-cなどで中断すると、その位置にプロンプトが出てしまうので、trap [3] を使って、後始末をするようにしても良いかと思いますが、今回は省略しています。また、プログレスバー [4] を表示するのも良さそうです。

サマリー情報

上に述べたように分割したファイルを受け渡す場合は、受け取った側がこちらと同じフォルダ・ファイル構成を再現できたのか、確認する手段が欲しいところです。そこで、サマリー情報を送る方法を紹介します。

以下の通り、アイテムのリストと、それぞれのファイルのMD5を記録することが出来ます:

受け側は、分割されたアーカイブを受け取って展開したあと、

のようにすることで、全てのフォルダ・ファイルを正しく受け取ることが出来たか、確認することができます。

まとめ & Known Bug

如何でしたか? 今回は、大量のファイルを分割して送る方法、また、正しく受け渡せたのか確認する方法について紹介しました。よろしければ、活用してみてください。

さて、実は、今回のスクリプトにはバグがあります。実は、

のようなディレクトリ構成の場合、

という動きをしてしまうのです。これでは、同じファイルが複数のアーカイブに入ってしまいます。これについては原因はわかっている (そして、それほど困っていない) ので、いずれ直したいと思いますが、読者の皆様もパズル感覚で修正案を考えていただければ、と思います。

参考文献

[1] Shellの出力でカーソルを移動させる
[2] Linux Command Line Adventure: tput
[3] shellのtrapについて覚え書き
[4] シェルスクリプトにプログレスバーを追加する方法