読者です 読者をやめる 読者になる 読者になる

53歳限界プログラマの憂鬱

SU/CAR-ST-APplication-cellsから派生したプログラマのブログ

本家はこちら↓
f:id:sucar:20151115183011p:plain

SU/CAR-ST-APplication-cellsの安倍野ミックスと申します
来訪ありがとうございます
シストレツールを自作してます

f:id:sucar:20150414193802p:plain

awkで$数字でなく$列名で計算(@includeの活用)

awkは便利です

なので、なるべくエクセルじゃなくawkを活用しようと考えている今日この頃・・・

今、システムの大規模改良を目論んでいて、C言語ソースから大幅に手を入れようと思っているのだけど、なかなかC言語でのシステムの出力データのフォーマットが決まらない・・・

これが決まってないと、その出力を入力とするツールがどうにもならないのです

awkにせよ、エクセルにせよ、列がずれると使い物にならない(方法はあるのかもしれないけどよくわからない)

R言語ならデータフレームに取り込んで、データフレーム$列名でアクセスできる

だけど・・・

エクセルはともかくawkでは何とかしたい

ということで、どんくさいけどこんな方法を考えてみた(たぶんもっとエレガントな方法があるんじゃないかと思うのだけど・・・)

まず、列名付きのcsvデータを準備

扱えるフォーマットは2種類

f:id:sucar:20170205102509p:plain

↑1行目はコメント行:約束として最初のセルに #1 と書くことにする

2行目に列名indexが記述される

f:id:sucar:20170205102752p:plain

↑コメント行なし 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してあげればよい

で、indexfunc.awkawkを使って

以下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

こんな感じで

f:id:sucar:20170205104717p:plain

一応うまくいった感じ

これで、データのフォーマットがどんなに変更されても列名さえ変化なければawkスクリプトは変更する必要はない

ただ、気になる点として・・・・

変数名を間違ってもエラーにならず、0が入るだけで$0が参照され、そのまま処理が進んじゃうとこが、ちょっと・・・

まあ気を付けるしかないか