web-dev-qa-db-ja.com

タブを区切り文字としてbashで行を配列に分割する

次の形式のファイルがあり、タブで区切られています

a   k   testis  adult   male    8 week  rRNA
b   k   testis  adult   male    8 week  rRNA
c   k   testis  adult   male    8 week  rRNA

各行でなんらかの操作を実行したいので、whileループを使用しています。タブで各行を分割してから、6番目の列である8 week変数内。このコードを使用していますが、必要なものを取得できません

while read -r line; do tmp=(${line///}); col6=${tmp[5]}; echo "$col6"; done < file.txt

これは8ではなく8 week。 8週間は8と週の間にスペースがあるので、タブで行を分割したいと思います。

6
user3138373

配列の割り当てtmp=(${line///})は、IFSに含まれるすべての文字の値を分割します。これには、デフォルトでタブ、およびスペースおよび改行が含まれます。 (空の置換が何をするのかわかりません。)タブでのみ分割するには、IFSを次のように設定します。

foo=$'a\tk\testis\tadult\tmale\t8 week\tRNA'
IFS=$'\t'
tmp=($foo)
echo "${tmp[5]}"

それでもグロビングは問題として残っていますが、すでにwhile readを使用しているため、read -a tmp(少なくともBashでは)を使用できますが、IFSに基づいて入力行を分割します。そして、フィールドを名前付き配列の要素に分離します:

$ while IFS=$'\t' read -r -a tmp ; do
    echo "${tmp[5]}"
done <<< $'a\tk\testis\tadult\tmale\t8 week\tRNA'

これは8 weekを出力します。これのもう1つの利点は、IFSの変更がreadの期間中のみ有効であり、スクリプトの残りの部分では有効でないことです。

もちろん、フィールドの数/意味がわかっている場合は、readを分割して名前付き変数を分離することができます。

... IFS=$'\t' read -r col1 col2 col3 ...

または、その1列だけを印刷する場合は、cutを使用します。

cut -d$'\t' -f 6  < file.txt
12
ilkkachu