どうも、NIPPAです。
久しぶりにshellのネタです。
pythonなどの他のスクリプトでファイルの内部を1行ずつ取り扱うことは比較的簡単ですが、
shell(bash)ではどう取り扱うのかを調べてみました。
環境
MacOS 10.14 Mojave
Shellでのファイル1行ずつの取り扱い方
1つ目のイメージは、ファイルの中身を読み込み、1行ごとに配列に入れ、配列を1行ずつ読み込む方式になります。
2つ目は無理やりですが、ファイル内部の行を指定して読み込み、繰り返す方式です。
この2つのやり方を実際に、行ってみます。
テスト用のファイルの作成
1から1000までの整数が入ったテキストファイルを用意します。
touch sample.txt for i in `(seq 1 1000)` ; do echo $i >> sample.txt done
ファイルの中身をすべて読み込み、配列に入れる方式
1度ファイルをすべて読み込みます。その際に、区切り文字の環境変数を指定して、配列に分けます。
test1.sh
に以下を書き込みます。
# 環境変数の指定(ここでは改行コード) IFS=$'\n' # fileをすべて読み込み、改行区切りで配列に代入 file=(`cat sample.txt`) # 配列をループを回して表示 count=0 for i in "${file[@]}" ; do count=$(($count + 1)) echo $count $i done
各行が表示されます。
行をしていしてファイルを読み込む方式
test2.sh
に以下を書き込みます。
# ファイルの行数を取得 max=(`cat sample.txt | wc -l`) # 配列をループを回して表示 count=0 while [ $count -le $max ] ; do count=$(($count + 1)) i=(`sed -n $count sample.txt`) echo $count $i done
2つの方法の比較
実行時間を図ってみます。
# test1の計測 time sh test1.sh # test2の計測 time sh test2.sh
結果をまとめた表になります。
test1.sh | test2.sh | |
---|---|---|
real | 0m0.036s | 0m4.728s |
user | 0m0.024s | 0m1.620s |
sys | 0m0.006s | 0m2.591s |
圧倒的にすべてを読み込み後に、操作する方が早いです。
test2.sh
の方は毎回ファイルIOがあるため、その分遅くなります。
メモリにのせたあとの操作の方が圧倒的に速いのは、よく知られていますよね。
感想
bashでも工夫次第でファイルを1行ずつ扱う事ができます。
それに加え、とりあえずメモリにのせてから操作することを基本として、
メモリにのり切らないときには、ファイルを利用が良さそうですね。