IT技術で仕事を減らしたい!

ITエンジニアのメモ+α

shell ファイルの中身を1行ずつ取り扱う

どうも、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行ずつ扱う事ができます。

それに加え、とりあえずメモリにのせてから操作することを基本として、

メモリにのり切らないときには、ファイルを利用が良さそうですね。