2015/09/24

Linuxでファイルを分割・結合する方法(コマンド)

ここでは、ファイルを一定の情報量(データの長さやテキストデータにおける行数)で複数のファイル群に分割するコマンドと分割されたファイル群を結合するコマンドについてを扱う。

本記事は以前splitcatの2つのコマンドについての記事とp7zipを用いたファイルの分割・結合についての記事を統合した上で一部内容を修正したもので、前者は2008年2月、後者は2013年3月に書かれた。

  1. 単純分割・単純結合用のコマンド(splitとcat)
    1. ファイルを単純分割する
      1. 分割方式
      2. 分割後ファイルの接頭辞(prefix)と接尾辞(suffix)
      3. 接頭辞部分を指定する
      4. 接尾辞部分の長さと形式を指定する
      5. 出力先ディレクトリ
      6. 標準入力の内容を分割する
    2. 単純分割されたファイルを結合する
  2. p7zipを用いたファイルの分割と結合
    1. split/catによる単純分割/結合との違い
    2. 分割処理の実際
    3. 分割された書庫ファイルとその展開方法

単純分割・単純結合用のコマンド(splitとcat)

ファイルを単純分割する

単純にファイルを分割する[1]には、基本コマンド集 “coreutils” に含まれるsplitというコマンドを使用する。

分割方式

splitコマンドによる分割では以下のいずれかの方式(区切り方)でデータを区切ることができ、これらの内の1つをオプションで指定する。未指定時は1,000行ごとに区切られ、複数を同時に指定した場合はエラーとなって処理は行われない。

  • -l [行数]: テキストデータを指定行数で区切る
  • -b [バイト数]: (主にバイナリ=非テキスト形式のデータを)指定された長さ(バイト数)で区切る
  • -C [バイト数]: テキストデータを指定された長さで区切る指定だが、行の途中では切らないようにして[2]かつ、指定した長さを越えない範囲で可能な限り多くの文字数を含めるようにする

上の “テキストデータ” というのは、書式情報などを含まない文字情報のみのプレーンテキスト形式のデータを指す。

-b-Cのバイト数指定では、値の後ろに

  • “b” (1b=512バイト)
  • “k” (1k=1,024バイト=1KiB)
  • “m” (1m=1,048,576バイト=1MiB)

のいずれかを後ろに付けることで、分かりやすい表記で指定することもできる。

分割後ファイルの接頭辞(prefix)と接尾辞(suffix)

分割されたファイルは、既定では

  • xaa
  • xab
  • xac

のようなアルファベットの連番のファイル名で出力される。これでは分かりにくいため

  • “x” の部分の接頭辞部分
  • “aa” “ab” などの連番の接尾辞部分

をそれぞれ指定して分かりやすいものにすることができる。

接頭辞部分を指定する

splitコマンドの引数には入力ファイルの場所を指定するが、次の引数として文字列を指定すると、その文字列が接頭辞部分として使われる(“x” の部分の代わりになる)。

この文字列の末尾を “.” にすると末尾が拡張子の形になる。

(接頭辞部分を指定して分割)
$ split -l 100 /var/log/Xorg.0.log Xorg.0.log.
(分割されたファイルの一覧を表示・ファイル数は元のファイルのサイズによる)
$ ls
Xorg.0.log.aa  Xorg.0.log.ab  Xorg.0.log.ac  Xorg.0.log.ad  ...

上の例では接頭辞部分として指定した “Xorg.0.log.” の後ろに連番部分の “aa” “ab” “ac” …が続く形になっている。

接尾辞部分の長さと形式を指定する

-a [文字数]” オプションを付けることで接尾辞部分の文字数が指定できる。

(接頭辞部分と接尾辞長を指定して分割)
$ split -l 100 -a 3 /var/log/Xorg.0.log Xorg.0.log.
(分割されたファイルの一覧を表示・ファイル数は元のファイルのサイズによる)
$ ls
Xorg.0.log.aaa  Xorg.0.log.aab  Xorg.0.log.aac  Xorg.0.log.aad  ...

-dオプションを付けると、数字による接尾辞が使用できる。

(接頭辞,接尾辞長,数字接尾辞を指定して分割)
$ split -l 100 -a 3 -d /var/log/Xorg.0.log Xorg.0.log.
(分割されたファイルの一覧を表示・ファイル数は元のファイルのサイズによる)
$ ls
Xorg.0.log.000  Xorg.0.log.001  Xorg.0.log.002  Xorg.0.log.003  ...

出力先ディレクトリ

splitコマンドの出力ファイル群は基本的には現在の作業ディレクトリに書き出されるが、接頭辞部分にディレクトリ階層を含めて指定することで任意のディレクトリに出力されるようにすることができる。

(出力先ディレクトリを準備)
$ mkdir -p /tmp/work/out
(出力先ディレクトリを接頭辞部分に含めて分割)
$ split -l 100 -a 3 -d /var/log/Xorg.0.log /tmp/work/out/Xorg.0.log.
(分割されたファイルの一覧を表示・ファイル数は元のファイルのサイズによる)
$ ls /tmp/work/out/
Xorg.0.log.000  Xorg.0.log.001  Xorg.0.log.001  Xorg.0.log.003  ...

標準入力の内容を分割する

引数(入力ファイルの場所)を指定しないか “-” を指定した場合(接頭辞部分を指定する場合には必須)は標準入力の内容が読み込まれて分割される。

下はコマンドの出力を分割して書き出す例。

(dmesgコマンドの出力を分割して保存)
$ dmesg | split -l 100 -a 3 -d - dmesg.log.
(分割されたファイルの一覧を表示・ファイル数は元のサイズによる)
$ ls
dmesg.log.000  dmesg.log.001  dmesg.log.002  dmesg.log.003  ...

単純分割されたファイルを結合する

単純分割されたファイルを結合するには、splitと同様に基本コマンド集 “coreutils” に含まれるcatコマンド[3]を使用する。コマンド名の由来は “concatenate” からで、ぬこではない。

catの引数には、結合したいファイルの場所を順番に(結合したい数だけ)続けて指定する。

$ cat [分割ファイル1] [分割ファイル2] [分割ファイル3] ... > [結合後の出力ファイル]

splitで分割されたファイルの接尾辞は(アルファベット形式でも数字形式でも)シェルから “*” でパターン指定したときに内部的に整列される[4]順番がファイル結合時の順番と同一になるように生成されるので、結合時に順番を気にする必要はない。

実際の形としては

$ cat [接頭辞部分]* > [出力ファイルの場所]

のようにしてできる。上でXorg.0.logを分割したファイル群の場合は

$ cat Xorg.0.log.* > Xorg.0.log

となる。

p7zipを用いたファイルの分割と結合

7-Zipのコマンド版をGNU/Linuxなどへ移植したp7zipでは、7z形式で圧縮をする際にボリュームというものを指定すると圧縮後のファイル(書庫)が分割された形で出力でき、展開する際には最初のファイルを指定することで後ろのファイル群が次々と処理されて元のファイルが書き出される。この仕組みにより、1つのファイルを細かく分割して保存できる。

split/catによる単純分割/結合との違い

  • splitによる分割とcatによる結合(以下 “単純分割/結合” とする)ではデータを単純に指定された長さで切っているだけなので、分割処理時に圧縮をかけることはできない
  • 分割7z書庫では複数のファイル群をまとめたものを(複数ファイルに)分割保存することができるが、単純分割/結合では分割する対象(元のデータ)は単一のファイルに限られる
  • 分割7z書庫は中身が正常に取り出せるか(書庫が破損していないか)を書庫自身を用いてテストすることができるが、splitでの分割では結合後のファイルについてMD5やSHA-1などのダイジェストを正常なものと比較しないと破損していないかが確認できず、確実に破損チェックがしたい場合は別途ダイジェストの内容を控えておく必要がある

分割処理の実際

分割を行う場合、 “-v[分割サイズ][k,m,gなど]” のオプションを引数(入力ファイルの場所)よりも後ろに付ける。例えば書庫の各ファイルを10MiBにしたければ “-v10m” を指定する。

元のデータが圧縮済みの形式で圧縮の余地がないような場合は無圧縮にして処理時間を短縮することもでき、その場合は “-mx=0” を指定する。7z形式における圧縮率の既定値(“-mx=” 指定なしの場合の値)は “5” でこれよりも高い圧縮率が指定可能なので、最大限の圧縮をしたい場合は “-mx” (“-mx=9” と等価)を指定する。

(最大圧縮で各書庫を20MiBにする例)
$ 7z a /path/to/out.7z [入力ファイルの場所...] -mx -v20m

(無圧縮で各書庫を10MiBにする例)
$ 7z a /path/to/out.7z [入力ファイルの場所...] -mx=0 -v10m

分割された書庫ファイルとその展開方法

分割された書庫には “.001” “.002” “.003” のような連番の拡張子が付けられる。先頭のファイル(“.001” の拡張子のファイル)は7z書庫としての情報が先頭に含まれているが、2つ目のファイルからはそのような情報はない。

適当な3分割された書庫ファイルを作ってfileで調べると

$ file test.7z.*
test.7z.001: 7-zip archive data, version 0.3
test.7z.002: data
test.7z.003: data

となっている。[5]

展開時には先述した通り先頭のファイル(“.001” の拡張子のファイル)のみに対して展開を行うようにする。上記により、2番目以降のファイルを指定しても書庫としては処理されない。

(分割された7z書庫を展開)
$ 7z x /path/to/infile.7z.001

1番目のファイルを展開すると、続けて自動的に2番目以降のファイルが順に読み込まれて展開が行われる。

なお、分割された書庫は拡張子の順番でcatで結合してそれを単一の7z書庫(.7zファイル)として保存し、これを展開することもできる。

使用したバージョン:
  • coreutils 6.9, 8.23
  • p7zip 9.20, 9.20.1
  • file 5.11, 5.20
[1]: 元のデータの並びを保持しながら途中で切って複数のファイル群に分けること
[2]: 分割された各ファイルは、最後のファイルを除いて改行文字で終了する形になる
[3]: 結合後のファイルは標準出力から出されるので、このコマンドは(1つもしくは複数の)ファイルの内容を(結合して)端末に表示するためのコマンドとしても使える
[4]: bashのmanページ内の “パス名展開” も参照
[5]: 種類が “data” となっている部分は、ファイルによっては他のいずれかの種類に誤って判定されることがあるが、これはfileコマンドが基本的にファイル先頭の一部だけを読み込んで種類を判定しているためで、実際にその種類のファイルとして扱えるわけではない