Woman checking her email in a meeting
LinuxのシェルスクリプトでCSVファイルを扱う機会は多くあります。例えば、ログの集計やデータのフィルタリング、バッチ処理の自動化などでCSVを1行ずつ読み込み、それぞれのフィールドを個別の変数に分解して処理したいといったケースです。
本記事では、while read line
を使ってCSVファイルを1行ずつ読み取り、それをフィールドごとに変数に代入して処理を行う方法について、実例とともに丁寧に解説します。初心者でもすぐに実践できるよう、注意点や応用例まで取り上げています。
CSVファイルをシェルスクリプトで読み取る最も基本的な方法は、while read line
を使う方法です。これは以下のような構文になります。
while IFS= read -r line; do
echo "$line"
done < input.csv
このスクリプトでは、input.csv
の中身を1行ずつ読み取り、line
変数に代入し、それを表示しています。IFS=
はフィールドセパレータを空にして、read
が先頭・末尾の空白を削除しないようにしています。-r
オプションはバックスラッシュの解釈を抑制するため、特にCSVのような生データを扱う際に便利です。
CSVファイルの各行はカンマで区切られていることが多いため、IFS=','
を指定して、readコマンドで分割代入が可能です。以下に例を示します。
while IFS=',' read -r name age gender; do
echo "名前: $name"
echo "年齢: $age"
echo "性別: $gender"
done < input.csv
たとえば、input.csv
に以下のようなデータが入っていた場合:
田中,30,男性
佐藤,25,女性
このスクリプトを実行すると、各行が3つの変数(name, age, gender)に分解され、それぞれの情報として出力されます。
以下のようなCSVファイル(people.csv)があるとします。
田中,30,男性
佐藤,25,女性
鈴木,40,男性
この中から年齢が30歳以上の人だけを表示するスクリプトを作ってみましょう。
#!/bin/bash
while IFS=',' read -r name age gender; do
if [ "$age" -ge 30 ]; then
echo "$name($age歳、$gender)"
fi
done < people.csv
このスクリプトを実行すると、以下のように出力されます:
田中(30歳、男性)
鈴木(40歳、男性)
read
コマンドによって行が分解され、条件に一致する行だけを処理できます。
CSVファイルの最終行に改行がないと、read
が正しく読み込めない場合があります。これを防ぐには、CSVを保存するときに必ず最終行にも改行を入れるようにしましょう。
readで指定した変数の数とCSVのフィールド数が一致しない場合、余ったフィールドはすべて最後の変数にまとめて入ります。逆にフィールドが足りない場合、未指定の変数は空になります。
# 4列目が存在しないとき、locationは空になる
while IFS=',' read -r name age gender location; do
echo "$name - $location"
done < input.csv
フィールド数が可変な場合、read
で指定する変数は1つだけにして、後からcut
やawk
などでフィールドを切り出す方法も有効です。
while IFS= read -r line; do
name=$(echo "$line" | cut -d',' -f1)
age=$(echo "$line" | cut -d',' -f2)
echo "$nameは$age歳です"
done < input.csv
あるいはawk
を使えば、より簡潔に書くこともできます:
awk -F',' '{ if ($2 >= 30) print $1"さんは"$2"歳です"; }' input.csv
ループの中で外部コマンドを使ってさらに処理を加えることも可能です。たとえば、APIにデータを投げるとか、ファイル出力するなど。
while IFS=',' read -r name age gender; do
curl -X POST -d "name=$name&age=$age&gender=$gender" https://example.com/api
done < input.csv
このようにすれば、CSVの各行のデータをもとに外部サービスと連携することも可能です。
ファイルだけでなく、コマンドの出力結果もread
で読み込むことができます。
ps aux | while read -r line; do
echo "$line" | grep apache
done
また、プロセス置換を使えば、ファイルディスクリプタの扱いもスマートにできます。
while IFS=',' read -r name age gender; do
echo "$name($age歳、$gender)"
done < <(cat input.csv)
while read line
を使ったCSVファイルの処理は、非常に柔軟で多用途に使えるシェルスクリプトの基本テクニックです。フィールドごとの変数代入を理解することで、CSVを自由自在に操作することができ、データ処理の幅が大きく広がります。
簡単なログ処理から業務レベルのバッチ処理まで、さまざまな場面で活用できるので、ぜひ手を動かして実践してみてください。