要件
TSV(タブ区切り)データを1行分持ってきて、各データを配列に入れたくなりました。
- なるべく速く
- 空データは空データとして格納する
- 特殊文字(タブ以外)を許容する
結論
各データをシングルクォーテーションで括って配列に代入します。
TSVデータ行が変数STR
に入っているとして
$ eval ARRAY=("$(sed -e "s/'/'\\\\''/g" -e "s/\t/'\t'/g" -e "s/^/'/" -e "s/$/'/" <<< "$STR")")
原理
eval
については以前の投稿 bash で ls 結果を配列に入れる - Qiita と同じです。
今回は、上記記事でls
の--quoting-style=shell-always
がやってくれていたことをsed
でやりました。
sedでやっていること
例を示しながら書いてみます。
タブ部分はわかりやすいように<TAB>
と書いています。
sed前:aaa<TAB>b b<TAB><TAB>dd'dd
sed
では以下の処理を行っています
- シングルクォーテーションをエスケープ(
'
→'\''
)。
aaa<TAB>b b<TAB><TAB>dd'\''dd
- 先頭と末尾にシングルクォーテーションを配置。
'aaa<TAB>b b<TAB><TAB>dd'\''dd'
- タブの前後にシングルクォーテーションを配置。
'aaa'<TAB>'b b'<TAB>''<TAB>'dd'\''dd'
sed後:'aaa'<TAB>'b b'<TAB>''<TAB>'dd'\''dd'
お試し
タブ区切りの文字列を用意します。
$ # テストデータ作成
$ STR=$(echo -e "\tbbb\tc c\t\te'e'e\t")
$ # 確認
$ echo "\"$STR\""
" bbb c c e'e'e "
配列に代入します。
$ # 配列に代入
$ eval ARRAY=("$(sed -e "s/'/'\\\\''/g" -e "s/\t/'\t'/g" -e "s/^/'/" -e "s/$/'/" <<< "$STR")")
結果を確認します。
$ # 配列の中身を確認
$ for VAL in "${ARRAY[@]}"; do echo "$VAL"; done
bbb
c c
e'e'e
$ # ↑最後の空文字も入っている
空のデータもちゃんと入りました。
発展:複数行
TSVファイル(複数行)の各行について処理したい場合は
while read -r LINE; do
eval ARRAY=("$LINE")
# 各行についての処理をここに書く
done < <(sed -e "s/'/'\\\\''/g" -e "s/\t/'\t'/g" -e "s/^/'/" -e "s/$/'/" "$FILE")
sedの実行が1度で済むのでこれが速そう。
発展:TSV以外
区切り文字の判別はsedの-e "s/\t/'\t'/g"
が要になっている。
カンマ区切りのファイルを入力としたい場合はここを-e "s/,/'\t'/g"
とすれば良い。