■ はじめに
シェルで、ヘッダー付きのCSV / TSVファイルの読み込み その一部を列を配列として扱いたいので、調べてメモっておく。
Memo
* CSV = Comma Separated Values(カンマ区切り) * TSV = Tab Separated Values(タブ区切り) * DSV = User-Defined Separated Values (ユーザ定義区切り)
目次
【1】CSVファイルを読み込み出力する 【2】ヘッダー(1行目)を除外して出力する 【3】TSVファイルを読み込む 【4】Tips 1)ファイルの読み込み 2)read / IFS 3)カウントアップ 4)sed
【1】CSVファイルを読み込み出力する
第一段階として、配列に入れて出力するだけのサンプルを作ってみた。
基本的な考え
* ファイルを標準入力として渡す => 以下の「【4】Tips の 1)ファイルの読み込み」を参照 * 上記をそのまま read コマンドによって配列として受け取る => 以下の「【4】Tips の 2)read / IFS」を参照
サンプル
sample_csv.sh
#!/bin/bash parse_csv() { # ${1} : CSV file (e.g. 'sample_csv.csv') readonly CSV_FILE="${1}" declare -a csv_data line_number=1 while IFS=, read -a csv_data; do for value in "${csv_data[@]}"; do echo "line_number = ${line_number}, value = ${value}" done # count up line_number=`expr $line_number + 1` done < "${CSV_FILE}" } # Call the function parse_csv "sample_csv.csv"
id,db_name,table_name 1,db1,sample_table1_1 2,db1,sample_table1_2 3,db2,sample_table2_1
出力結果
$ ./sample_csv.sh line_number = 1, value = id line_number = 1, value = db_name line_number = 1, value = table_name line_number = 2, value = 1 line_number = 2, value = db1 line_number = 2, value = sample_table1_1 line_number = 3, value = 2 line_number = 3, value = db1 line_number = 3, value = sample_table1_2 line_number = 4, value = 3 line_number = 4, value = db2 line_number = 4, value = sample_table2_1
【2】ヘッダー(1行目)を除外して出力する
ヘッダー部分を除外したいので調べてみたら 以下のサイトが見つかった
sed を使って、ヘッダー部分を除外している。 (詳細は、以下の「【4】Tips の 4)sed」を参照)
サンプル
sample_csv.sh
#!/bin/bash parse_csv_without_header() { # ${1} : CSV file (e.g. 'sample_csv.csv') readonly CSV_FILE="${1}" sed 1d "${CSV_FILE}" | while IFS=, read -r id db_name table_name; do echo "id ${id} - db_name=${db_name} / table_name=${table_name}" done } parse_csv_without_header "sample_csv.csv"
出力結果
$ ./sample_csv.sh id 1 - db_name=db1 / table_name=sample_table1_1 id 2 - db_name=db1 / table_name=sample_table1_2 id 3 - db_name=db2 / table_name=sample_table2_1
【3】TSVファイルを読み込む
サンプル
sample_tsv.sh
#!/bin/bash parse_tsv_without_header() { # ${1} : CSV file (e.g. 'sample_csv.csv') readonly CSV_FILE="${1}" sed 1d "${CSV_FILE}" | while IFS=$'\t' read -r id db_name table_name; do echo "id ${id} - db_name=${db_name} / table_name=${table_name}" done } parse_tsv_without_header "sample_tsv.csv"
sample_tsv.csv
id db_name table_name 1 db1 sample_table1_1 2 db1 sample_table1_2 3 db2 sample_table2_1
出力結果
$ ./sample_tsv.sh id 1 - db_name=db1 / table_name=sample_table1_1 id 2 - db_name=db1 / table_name=sample_table1_2 id 3 - db_name=db2 / table_name=sample_table2_1
【4】Tips
1)ファイルの読み込み
https://qiita.com/tag1216/items/7ce35b7c27d371165e56
# より抜粋 # ファイルの内容をコマンドの標準入力へ渡す command < file
2)read / IFS
readコマンド
read [variable1, …] * 標準入力から行を 1 行読み取り、 その行を複数のフィールドに分割し、 各 variable に割り当てます * 環境変数 IFS を使用する
環境変数 IFS
* IFS = Internal Filed Separator (内部ファイル区切り文字) => 区切り文字を設定できる => 詳細は、以下の関連記事を参照のこと
https://dk521123.hatenablog.com/entry/2024/01/24/234634
3)カウントアップ
line_number=`expr $line_number + 1`
exprコマンド
* 計算式を評価するコマンド
https://atmarkit.itmedia.co.jp/ait/articles/1712/28/news019.html
# | オプション | 説明 |
---|---|---|
1 | -a | 読み込んだ単語を配列にセットする |
2 | -r | エスケープ文字を無効 |
https://atmarkit.itmedia.co.jp/ait/articles/1811/28/news003.html
https://linuxcommand.net/read/
4)sed
sed を使って、ヘッダー部分を除外している。 => sed 1d : 1(行目) d (delete:削除) なお、sedについは、以下の関連記事を参照のこと。
sedコマンド
https://dk521123.hatenablog.com/entry/2019/11/23/101625
参考文献
https://genzouw.com/entry/2019/02/06/081505/765/
https://qiita.com/SoarTec-lab/items/4475ba6de612fba3f163
関連記事
シェル ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2014/10/23/005406
シェル ~ 文字列抽出あれこれ ~
https://dk521123.hatenablog.com/entry/2021/08/03/160901
シェル ~ 環境変数 IFS ~
https://dk521123.hatenablog.com/entry/2024/01/24/234634
sedコマンド
https://dk521123.hatenablog.com/entry/2019/11/23/101625