awkで$数字でなく$列名で計算(@includeの活用)
awkは便利です
なので、なるべくエクセルじゃなくawkを活用しようと考えている今日この頃・・・
今、システムの大規模改良を目論んでいて、C言語ソースから大幅に手を入れようと思っているのだけど、なかなかC言語でのシステムの出力データのフォーマットが決まらない・・・
これが決まってないと、その出力を入力とするツールがどうにもならないのです
awkにせよ、エクセルにせよ、列がずれると使い物にならない(方法はあるのかもしれないけどよくわからない)
R言語ならデータフレームに取り込んで、データフレーム$列名でアクセスできる
だけど・・・
エクセルはともかくawkでは何とかしたい
ということで、どんくさいけどこんな方法を考えてみた(たぶんもっとエレガントな方法があるんじゃないかと思うのだけど・・・)
まず、列名付きのcsvデータを準備
扱えるフォーマットは2種類
↑1行目はコメント行:約束として最初のセルに #1 と書くことにする
2行目に列名indexが記述される
↑コメント行なし 1行目に列名indexが記述される
で、awkで、例えば、hjm1を抜き出したかったら
print $2
とか書くのだけど これを
print $hjm1
と書けるようにしたいという話
いろいろ方法を考えて、連想配列使えばできそうなんだけとそれだと
print $ar["hjm1"]
とかなりそうで、記述が美しくない
で、gawk 4.0 以降だと@include文が使えるらしいのでこれを活用してみるテストを実施
以下test1.awk
#使い捨て関数をインクルード @include "indexfunc.awk" BEGIN{ FS = "," #使用する変数に大きなマイナス数を入れておく owa1=hjm1=-10000 #使い捨て関数実行 indexfunc() #使用する変数の和がマイナスならエラー if (owa1+hjm1<0) { print "error\n" exit } } NR==1{ if ($1!="#1") { hd=1 } else { hd=2 } } #本体 NR>hd{ printf("%s=%8.2f : %s=%8.2f\n","hjm1",$hjm1,"owa1",$owa1) }
こんな感じで、要はhjm1=2 owa1=5を代入してくれる関数を別途作ってincludeしてあげればよい
以下test.awk
BEGIN{ FS = "," print "function indexfunc() {\n" } NR==1{ if ($1!="#1") { for(i=1;i<=NF;i++) printf("%s=%2d\n",$(i),i) print "}\n" exit } else { hd=2 } } NR==hd{ for(i=1;i<=NF;i++) printf("%s=%2d\n",$(i),i) print "}\n" exit }
ってやって作成する
これらを纏めるシェルスクリプトを作成
以下awktest
#!/bin/bash awk -f test.awk $1 > indexfunc.awk awk -f test1.awk $1 rm indexfunc.awk
こんな感じで
一応うまくいった感じ
これで、データのフォーマットがどんなに変更されても列名さえ変化なければawkスクリプトは変更する必要はない
ただ、気になる点として・・・・
変数名を間違ってもエラーにならず、0が入るだけで$0が参照され、そのまま処理が進んじゃうとこが、ちょっと・・・
まあ気を付けるしかないか