シェルスクリプト入門(2)
※ 編集注:前作シェルスクリプト入門(1)の続編です。まだ読み終わってない方はそちらを先にどうぞ。
テーブルファイルの操作と言えばRです。 (※ 編集注:Pythonでもできます。) が、そこまでbashで書いてきたのに、R呼び出して変数再設定して…面倒くさいから嫌だ!! ってことないでしょうか。
Rの機能を代替するのは無理ですが、せめてほんの少し、 例えば、テーブル中の値をそれぞれbashの変数に入れれたら、 Rを呼び出さずに完結できたりします。
要は、$ mat_i_j=i行j列目の要素
で変数を格納していきます。
対象ファイル名を、table.txtで、タブ区切り、中身は以下みたいの。
a b c
1 2 3
d e f
これの各要素を、$mat_i_j
に格納していきます。
一例として、以下のスクリプトでできます。
配列つかったりしてもっといいスクリプトもきっとあります。
bashは汚いスクリプトでもたいてい速く動いてくれるので成長しないですね。
#!/bin/bash
row=0 ## 行番号に使う変数の設定。
while read x1 x2 x3 ## 解説①
do
row=`expr $row + 1` ## 1行ずつ読んでくので、1ずつ足していく。
for col in `seq 1 3` ## 今読んでる行での列番号をfor文で回す。
do
eval mat_${row}_${col}=`eval echo \\$x${col}` ## 解説②
done
done<table.txt
### 変数mat_$i_$j を使った処理が続く。
時間のある人用に解説です。 少し小技があります。
1) while readの使い方
よく見かけるのは、cat
からパイプでwhile read
につなぐやつです。
cat table.txt | while read x1 x2 x3
ファイルを一行ずつ読んで、各列の要素をread
の後ろに置いた変数名(x1,x2,x3)
に格納していきます。変数名の個数は任意です。ここでは列の数に合わせてます。
各行ごとに、do
~done
の間で、$x1
,$x2
,$x3
が使えるようになります。
が、しかし、パイプでwhile
に入ってしまうと、パイプ内はパイプ内で完結するため、
do
~done
の中で変数操作をしても、done
の後では、その中身が空っぽになっちゃいます。
これを回避するためには、パイプを使わないということで、リダイレクトで、
done
の後ろに
done<table.txt
を書きます。 読みにくいですよねー。
2) evalの使い方
今回のmat_$i_$j
のように、変数名に変数($i,$j)
を使って値を格納する時には、eval
を使います。
eval
は、その後に書いた文をもってきて、bashスクリプトとして評価(evaluate)します。
なので、i=2, j=3
として、
eval mat_${i}_${j}=aaa
は、
mat_2_3=aaa
をスクリプトとして評価しろ、ということになり、
mat_2_3
という変数名に、aaa
が入ります。
(ちなみに、どこまでが変数名か分からなくなる状況では、変数名を{}でくくります。ここではiとj。)
変数を使った変数名の中身を出力させる場合には、echoとevalを組み合わせます。
col=1
として、
eval echo \$x${col}
と書けば、まず、eval
が$col
の中身を出してからスクリプトとして評価するので、
(xの\(には\がかかってるので無視されます)
echo $x1
と書いていることになり、通常のecho
で書いたように、$x1
の中身が出力されます。
xの\)にかかってた\は、eval
での評価で消費されて、echo
内にはなくなります。ここ重要。
やりたいことは、eval echo
で出してきた値を、変数を使った変数名に格納することです。
eval mat_${i}_${j}=aaa
のaaa
部分にeval echo
を直接もってきても、機能しません。
eval echo
のままでは、まだ値ではなくスクリプトだからです。
なので、そのスクリプトを実行させて値を出力させたものを、aaa
の部分に書きます。
そういう時は、アクサングラーブ(` シフト押しながら@)でくくります。
アクサングラーブは、その中にあるスクリプトの実行結果を出力します。 なので、
test=`echo $k`
とすれば、$k
の中身が出力されて、test
に格納されます。
row
に1ずつ足していくとこでも使ってます。よく見る方法です。
for
文使わなくていいので、見た目がすっきりします。
では、
eval mat_${i}_${j}=`eval echo \$x${col}`
と書けば、mat_2_3
に$x1
の中身が代入されるはず!
となるのですが、不完全です。
アクサングラーブでの評価で、\
が一個消費されてしまうので、実行するeval echo
の文が、
eval echo $x${col}
となるので、eval
での評価時に$x
の中身(設定してないので空っぽ)と$col
が出されてしまって、
echo (空)1
となって、最終的に、mat_2_3
には$x1
ではなく、$col
の中身である1が代入されてしまいます。
なので、
eval mat_${i}_${j}=`eval echo \\$x${col}`
と、\を一個増やして書けば、目的達成です。 めでたしめでたし。
※ 編集注 : 記事はめでたく終わりましたが、アクサングラーブがマークダウンと干渉してしまいました。試行錯誤の結果、ところどころテキストが混じって読みにくくなってしまいました。すみません。
- 前の記事 : TCGAbiolinksとその使い方
- 次の記事 : pandasのpivot_tableを用いた高速データ処理
- 関連記事 :