当サイトではアフィリエイト広告を利用しています。

【コピペ解決】splitコマンドの「-l」でファイル均等に分割をする方法!

当サイトではsplitコマンドでファイル分割する方法を既に紹介しましたが、、、

splitコマンドで物凄く便利な「-n」オプションは比較的新しいオプションで、古めもしくは軽量版のディストリビューションでは使えない可能性があります。

split: invalid option -- 'n'
Try 'split --help' for more information.

こういった場合、ファイルを行数単位で3分割したい!といった場合は「-l」を使うので、予め分割元のファイルの行数を把握しておいてそれを分けたいファイル数で割ってその数字を「-l」の引数に入れる必要があり、非常に面倒くさい!!

これらの作業を一発で解決するスクリプトを作成します!

使用するサンプルデータ

まずは、分割元ファイルを作成します。

sample.txt

line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
line 9
line 10

これをsample.txtとして保存しておきます。

split -lしか使えないのにファイル数指定で分割できるファイル分割スクリプト(簡易版)【コピペで使える】

以下のスクリプトをsplitN.shで保存してみてください!

 #!/bin/bash
echo "分割したいファイル名を入力してください。"
read file
echo "分割するファイル数を入力してください。"
read parts
lines=$(wc -l < "$file")
lines_per_file=$(( (lines + parts - 1) / parts ))
split -l "$lines_per_file" "$file" chunk_

🔰 Linuxを試せる環境がない方へ

コマンドなどを実際に試してみたいけれど、Linux環境がない…
そんなときは、「さくらのVPSを使えば簡単に自分専用のLinux環境が手に入ります!

  • ✅ 月額524円(税込)〜手軽に始められる
  • ✅ UbuntuやDebianなど、好みのOSが選べる
  • ✅ SSH接続でターミナル操作もバッチリ
  • ✅ 日本国内の大手サービスで安心・安定

さくらのVPSでLinux学習をはじめる \ あなただけのLinux環境を5分で構築! /

コード解説

コード解説だけではわからないとおもうので、実際に実行してみたり、当ページの実行結果と照らし合わせて見てみてください。

1行目の「#!/bin/bash」はbashで実行されるシェルスクリプトですよ~ということを示しています。

2と4行目は標準出力でメッセージを表示させています。

echo "XXXXX"

3と5行目のreadコマンドはユーザからの入力を受け取って、それぞれの変数に格納しています。

read YYYY

6行目では指定されたファイルの行数を把握しています。

lines=$(wc -l < "$file")
  • wc -l で指定ファイルの行数を取得します。
    wcコマンドは「行数、単語数、ファイル容量」カウントするコマンド(word count)ですが「-l」オプションをつけることで行数のみを表示するようにしています。

  • $fileで設定すると変数linesに「10 simple.txt」といったようにファイル名も含まれてしまいますが、< "$file" とすることによりファイルの中身を wc に渡しているため、「10」という数値のみを変数に格納することができます。

7行目では分割後の各ファイルの行数算出しています。

lines_per_file=$(( (lines + parts - 1) / parts ))

10行あるファイルを3つに分割したいとき、分割後のファイルの行数はいくつにするか?というのを計算します。

通常は、10÷3=3.3333…ですが、、
「○○行」とするため、整数である必要がありますので、「3」となります。

ですが、、、

3分割したということは3行×3ファイルで9行分しか反映されていないという状態になってしまっています。

そのため、割り算の切り上げ方法を用いて計算しています。
「3」で切り捨てられていた小数点部分を全て切り上げて「4」として格納します。

8行目では実際に分割しています。

split -l "$lines_per_file" "$file" chunk_

7行目で決まった数値を使用して、splitコマンドの行数部分の引数として充てています。

実行結果

splitN.shの実行結果です。

$ bash splitN.sh
分割したいファイル名を入力してください。
sample.txt
分割するファイル数を入力してください。
3
$ cat chunk_aa
line 1
line 2
line 3
line 4
$ cat chunk_ab
line 5
line 6
line 7
line 8
$ cat chunk_ac
line 9
line 10

まず、splitN.shを実行後に分割するファイル名を聞かれるので分割したいファイル名を入力します。

そのあと、いくつのファイルに分割したいのかを数字で入力します。

すると、ファイル分割が実行されます。

分割後のファイルの行数を確認すると4,4,2で10行を確実に分割していることができていますが、「split -n」の実行結果とは異なり、4,3,3にはなってくれません。

ここが簡易版として紹介している理由で、指定行数を切り上げている都合上、可能な限り均等に分割するのではなく最後のファイルだけ余りみたいな扱いになってしまいます。

均等でなくてもファイルをある程度同じような行数で分割をして、移送して、移送先でまとめるといった作業であれば、このスクリプトで十分かとおもいます。

 

いや!split -n l/〇を再現したいという人もいるとおもうので、次は少しコードが複雑になりますが「split -n」と同様の分け方をしてくれるスクリプトを紹介します!

ファイル数指定で分割できるファイル分割スクリプト(split -n l/〇再現版)【コピペで使える】

splitコマンドは使っていませんが、代わりにsedコマンドを使用して、「split -n l/〇」を再現しています。

以下の内容を split_n_equally.sh という名前で保存してみてください

#!/bin/bash
echo "分割したいファイル名を入力してください。"
read file
echo "分割するファイル数を入力してください。"
read parts

lines=$(wc -l < "$file")
base=$(( lines / parts ))
extra=$(( lines % parts ))
start=1

for ((i = 0; i < parts; i++)); do
lines_this_file=$base
if [ $i -lt $extra ]; then
lines_this_file=$((base + 1))
fi

end=$((start + lines_this_file - 1))
sed -n "${start},${end}p" "$file" > "chunk_$(printf "%02d" $i).txt"
start=$((end + 1))
done

スクリプト解説

  1. ファイル名を取得します。
    echo "分割したいファイル名を入力してください。"
    read file

    ・ユーザに対して「どのファイルを分割したいか?」を聞きます。
    ・入力されたファイル名(例:sample.txt)をfileという変数に格納します。

  2. 分割するファイル数を取得します。
    echo "分割するファイル数を入力してください。"
    read parts

    ・ユーザに対して「何分割したいか?」を聞きます。
    ・入力された分割数(例:3)をpartsという変数に格納します。

  3. 分割前のファイルの行数をかぞえます。
    lines=$(wc -l < "$file")
    

    wc -l で、指定ファイルの行数をカウントします。
    < "$file" によって、ファイルの中身だけを wc に渡しています(ファイル名が付かない)。
    ・例として sample.txt が10行なら lines=10 になります。

    ここまでは、簡易版スクリプトと同様の流れです。

    ここから下が「split -n l/〇」に向けて変更された流れになります。

  4. 分割後のベースとなる行数とその余りを求めます。
    base=$(( lines / parts ))
    extra=$(( lines % parts ))
    

    ・変数baseに入れる値については簡易版と異なり分割前の行数を分割数で割った値の小数点を切り捨てた値を格納し、これを各ファイルに入る最低限の行数とされます。
    ・変数extraでは分割前の行数を分割数で割った余りを格納します。

    例:

    lines = 10
    parts = 3

    base = 10 / 3 = 3
    extra = 10 % 3 = 1
    

    → 各ファイルに3行ずつ入れ、余った1行は最初の1ファイル目に追加するようにします。

  5. 分割後ファイルの1行目は分割前ファイルの何行目かを定義します。
    start=1

    startは、何行目から何行目までを抜き出すか?の開始行番号です。
    最初は1行目から始まるのでstart=1

    次はFor文ループでファイル分割していきます。

  6. ファイル分割数までForループさせます。
    for ((i = 0; i < parts; i++)); do

    i を0から parts-1 までループさせます。
    分割数が3の場合は0,1,2でループするため3回ループします。

    つまり、分割するファイルの個数だけ処理を繰り返します。

  7. ループ内で分割後のファイルの行数を決定するのでそれ用の変数を作っておきます。
     lines_this_file=$base

    取り敢えず、ベースとなる最低限の行数を格納しておきます。

  8. if分岐で余っている行数を分配していきます。
     if [ $i -lt $extra ]; then
    lines_this_file=$((base + 1))
    fi

    最初の $extra 個のファイルには、1行多めに追加します。
    例えば、余りが2行なら、0番目と1番目のファイルにはそれぞれ base+1とします。

  9. 分割するファイルの終了行番号を計算します。
     end=$((start + lines_this_file - 1))

    start から lines_this_file 行分の 終了行番号(end) を計算します。
    例えば、ループの1週目はstart=1,lines_this_file=4なので、普通に足すとend=5となってしまい1~5行目を分割対象としてしまうため、-1を付けて変数endが4になるように調整します。

  10. 分割コマンドを実行
     sed -n "${start},${end}p" "$file" > "chunk_$(printf "%02d" $i).txt"

    ここで予め決めたstartとendの行番号に従ってsedコマンドでファイル分割をしていきます。

    ・sed -nを使って、指定した行番号の範囲のみを抽出します。
    ・例:sed -n '1,4p’ $file→分割元ファイルの1行目から4行目を表示
    ・この結果をcunk_xx.txtといったような連番ファイルとして保存します。
    ・printf “%02d"というのは数字をゼロ埋め2桁で表示しています。(00,01,02….)

  11. 次のファイル用に開始行数を更新しておきます。
     start=$((end + 1))

    次のファイルは、今の end の次の行から始まるので、endに+1したものをstart に代入して更新します。

  12. forループを閉じます。
    done
    

    ループの終了です。これで指定したファイル数分、繰り返して分割されます。

実行結果を見てみましょう!

実行結果

$ bash split_n_equally.sh
分割したいファイル名を入力してください。
sample.txt
分割するファイル数を入力してください。
3
$ cat chunk_00.txt
line 1
line 2
line 3
line 4
$ cat chunk_01.txt
line 5
line 6
line 7
$ cat chunk_02.txt
line 8
line 9
line 10

完璧!これで、「split -n l/N」相当の処理をシェルスクリプトで再現できました!

🔰 Linuxを試せる環境がない方へ

コマンドなどを実際に試してみたいけれど、Linux環境がない…
そんなときは、「さくらのVPS」を使えば簡単に自分専用のLinux環境が手に入ります!

  • ✅ 月額524円(税込)〜手軽に始められる
  • ✅ UbuntuやDebianなど、好みのOSが選べる
  • ✅ SSH接続でターミナル操作もバッチリ
  • ✅ 日本国内の大手サービスで安心・安定

さくらのVPSでLinux学習をはじめる \ あなただけのLinux環境を5分で構築! /