Bashシェルスクリプトで標準入力から配列を生成する “read -a” コマンドが便利
はじめに
Bash のビルトインコマンド “declare" の使い方紹介 ( その1 ) で 配列型の変数 について触れました。
その後 Bash のビルトインコマンド “declare" の使い方紹介(その2) で 大文字専用の変数 あるいは 小文字専用の変数 について取り扱ったので、少しだけ関係する read ビルトインコマンドについても触れておきます。
read を使うと、標準入力から読み込んだデータの取り扱いが用意になる場合があります。
検証環境
$ uname -moi
x86_64 MacBookPro10,1 Darwin
$ bash -version
GNU bash, バージョン 5.0.2(1)-release (x86_64-apple-darwin18.2.0)read ビルトインコマンドとは?
特徴を簡単に列挙してみます。
- 標準入力を読み、一行ずつ読み込む
- 終了コードは、行を読み込めたときは 0 、 読み込めなかったとき ( EOF も含む ) は 1
- ループの終了判定に使うことができる
- 引数にシェル変数名が指定し、読み込んだ行を変数に格納する
- 行末の改行は削除される
ベーシックな使い方として、ファイルの内容を1行ずつ読み込む処理として使われます。while コマンドと一緒にループ処理を記述する際に使われます。
事前準備 ( サンプルデータ作成 )
動作を見ていくために、適当なデータを作成しておきます。
$ cat <<EOF >> data.csv
a,b,c
d,E,F
G,h,i
1,2,3
4,5,X
EOF
# ファイルができたか確認
$ cat data.csv1 行ずつ読み込み、変数に代入
cat でいいよね、というぐらいに簡単な処理。
$ cat data.csv | while read line; do
echo "$line"
done
a,b,c
d,E,F
G,h,i
1,2,3
4,5,X1 行ずつ読み込み、列ごとにばらして変数に代入
これも cut コマンドでいいよね、というぐらいに簡単な処理ではあります。
# 列の区切り文字として、 "," を使うように変更
$ cat data.csv | while IFS=, read c1 c2 c3; do
# 今回は2列目だけを出力させてみる
echo "$c2"
done
b
E
h
2
5ポイントは IFS=, の部分。 read コマンド実行の際に、今回は環境変数 IFS として文字列 , を設定して実行しています。
ちなみに、環境変数 IFS はデフォルトでは スペース と タブ がセットされています。
つまり、 read コマンドはデフォルト挙動では スペース と タブ を列の区切り文字として扱います。
# このように空白とタブが出力される(わからない??)
$ echo "[$IFS]"
[
]1 行ずつ読み込み、列ごとにばらして変数に代入 ( ただし、1 列目だけでいい )
$ cat data.csv | while IFS=, read c1 x; do
# 今回は1列目だけを出力させてみる
echo "$c1"
done
a
d
G
1
4
$ cat data.csv | while IFS=, read c1 x; do
# xを見ると、2列目以降全て格納されている
echo "$x"
done
b,c
E,F
h,i
2,3
5,X不要な列は x という変数に突っ込んで捨てます。
x の部分を _ と記述する場合もあります。
$ cat data.csv | while IFS=, read c1 _; do
# 今回は1列目だけを出力させてみる
echo "$c1"
doneこの場合、 $_ は参照できません。
ちなみに $_ は少々特殊な組み込み変数の変数であり、条件を満たせば値が参照できます。
以下のエントリで詳しく取り上げています。
( 本題 ) 1 行ずつ読み込み、列ごとにばらして配列型の変数に代入
ようやく declare と関連するはなしにきました。read で読み込んだ列データを配列型の変数に代入することができます。
# `-a` オプション付きで read する
$ cat data.csv | while IFS=, read -a COLS; do
# 今回は2列目だけを出力させてみる
echo "${COLS[1]}"
done
c
F
i
3
XBash のビルトインコマンド “declare" の使い方紹介(その1) で取り上げたとおり、 declare -a で配列型の変数を定義できます。
read -a コマンドは、 declare -a 同様に配列型の変数を生成しつつ、標準入浴から読み込んだデータを分割し格納します。
特に列が大量にある csv データや tsv データを取り扱うときに便利です。read コマンドの後ろに変数を 30 も 40 も書いていられないし、 sed で処理すると正規表現が複雑になってしまう場合に有効です。
( 発展系 ) 1 行ずつ読み込み、列ごとにばらして配列+大文字型の変数に代入
更に発展形。 配列かつ大文字専用 の変数に read してみます。( Bash のビルトインコマンド “declare" の使い方紹介(その2) )
read -a 実行前に declare -u a コマンドで変数を定義するのがポイントです。
$ declare -u -a UPPER_COLS
$ cat data.csv | while IFS=, read -a UPPER_COLS; do
# 今回は2列目だけを出力させてみる
echo "${UPPER_COLS[1]}"
done
B
E
H
2
5ちゃんと値が大文字に変換されて出力されていますね。
ひとこと
また後日 read コマンドの便利な使い方を取り上げます。








ディスカッション
コメント一覧
まだ、コメントがありません