WANtaroHP (gawk Tips)

 


awk のスクリプトの基本構成

BEGIN{ データを読み込む前に行う処理 }
pattern { データを読み込みながら行う処理 }
END{ データ読み込み完了後に行う処理 }

awk のスクリプトの基本構成は上に示すとおり. patternを記載すると,その条件に合致する行の処理を行う.pattern を省略すると全行の処理を行う.

もし,データ読み込みを行わないで処理を行うなら,以下のように BEGIN で囲まれた部分のみを記述する.

BEGIN{ データを読み込む前に行う処理 }


基本

gawk -f awk_script.awk inp_data.txt > out_data.txt

この事例では,ファイルの設定は以下のとおり.

awk_script.awkawk スクリプト(awk のプログラム)
inp_data.txt awk で処理する入力ファイル名
out_data.txt awk で処理された結果を出力するファイル名


ARGC, ARGV の使用事例

事例(1)

実行用コマンド

gawk -f awk_ARGV_test.awk test1.txt para1 para2 para3 > out_ARGV.txt

awk スクリプト (awk_ARGV_test.awk)

BEGIN{
printf "ARGC=%d\n",ARGC
for(i=0;i<=ARGC-1;i++){
printf "ARGV[%d]:%s\n",i,ARGV[i]
}
}

出力結果

ARGV[0] にはプログラム名の gawk があてられ,-f でオプション指定されたスクリプト名をとばして test1.txt 以降が ARGV[1] から ARGV[4] にあてられる.この事例では引数の数を示す ARGC は 5 となる.

ARGC=5
ARGV[0]:gawk
ARGV[1]:test1.txt
ARGV[2]:para1
ARGV[3]:para2
ARGV[4]:para3

事例(2)

実行用コマンド

gawk -f awk_result_2dim.awk out_2dim0_002.csv 2 33 44 59 > result_2dim0.csv

awk スクリプト (awk_result_2dim.awk)

BEGIN{
nd =ARGV[2]
nu =ARGV[3]
ns1=ARGV[4]
ns2=ARGV[5]
for(i=2;i<=5;i++){delete ARGV[i]}
FS=","
sigs=0;sigr=0
n=nd*2*4
}

NR==nu{u=$5}
ns1==NR,NR==ns2{sigs=sigs+$6;sigr=sigr+$7}

END{printf "%d,%g,%g,%g\n",nd,u,sigs/n,sigr/n}

説明

上の awk スクリプトは,FEMの解析結果の打ち出し ( csv ファイル) の一部を読み取るものです. ここでの注意事項として,実行用バッチファイルの中で,スクリプト名の後ろに処理に必要となるパラメータを入力しています. ARGV[0] には「gawk」,ARGV[1] には入力ファイル名が格納され,ARGV[2] から ARGV[5] には数値を入力している「つもり」なのですが,「BEGIN」の中で必要な数値を変数に格納したら,ファイル名 ( ARGV[1] ) 以外の ARGV[] の配列要素を削除しています. これは,gawk は ARG[2] 以降もファイル名として読み込もうとしてエラーになってしまうため,これを避ける処置です. ちなみに「BEGIN」の中で ARGV[1] を削除すると,入力ファイル名が不定になり,うまく動きません.

データ読み込み処理部では,以下の処理を行っています.

  • NR==nu が真となる行について,値 u をセットする.
  • ns1==NR が真になる行から NR==ns2 が真になる行まで,sigs と sigr の総和をとる.


FILENAME, NR, FNR, NF の使用事例

入力サンプルデータ

test1.txt
0.1
0.2
0.3
0.4
0.5
test2.txt
1 10
2 20
3 30
4 40
5 50
test5.txt
1 10 100 1000 10000
2 20 200 2000 20000
3 30 300 3000 30000
4 40 400 4000 40000
5 50 500 5000 50000

実行用コマンド

gawk -f awk_NR_test.awk test1.txt test2.txt test5.txt > out_NR.txt

awk スクリプト (awk_NR_test.awk)

BEGIN{print  "FILENAME   NR   FNR    NF     $1     $2     $3     $4     $5"}
{
switch(FILENAME){
case "test1.txt":printf "%s %3d %5d %5d %6.1f\n",FILENAME,NR,FNR,NF,$1;break
case "test2.txt":printf "%s %3d %5d %5d %6d %6d\n",FILENAME,NR,FNR,NF,$1,$2;break
case "test5.txt":printf "%s %3d %5d %5d %6d %6d %6d %6d %6d\n",FILENAME,NR,FNR,NF,$1,$2,$3,$4,$5;break
}
}

上のスクリプトでは,switchを使用し場合わけしているが,下のスクリプトでも同じ処理ができる.

BEGIN{print  "FILENAME   NR   FNR    NF     $1     $2     $3     $4     $5"}
FILENAME=="test1.txt"{printf "%s %3d %5d %5d %6.1f\n",FILENAME,NR,FNR,NF,$1}
FILENAME=="test2.txt"{printf "%s %3d %5d %5d %6d %6d\n",FILENAME,NR,FNR,NF,$1,$2}
FILENAME=="test5.txt"{printf "%s %3d %5d %5d %6d %6d %6d %6d %6d\n",FILENAME,NR,FNR,NF,$1,$2,$3,$4,$5}

出力結果

NR は,読み込んでいるファイルの変更によらず,スクリプトの最初から最後までの読み込んでいる現在行を示す. FNR はファイルごとに読み込んでいる現在行を示す.NF は列数を示す.

FILENAME   NR   FNR    NF     $1     $2     $3     $4     $5
test1.txt   1     1     1    0.1
test1.txt   2     2     1    0.2
test1.txt   3     3     1    0.3
test1.txt   4     4     1    0.4
test1.txt   5     5     1    0.5
test2.txt   6     1     2      1     10
test2.txt   7     2     2      2     20
test2.txt   8     3     2      3     30
test2.txt   9     4     2      4     40
test2.txt  10     5     2      5     50
test5.txt  11     1     5      1     10    100   1000  10000
test5.txt  12     2     5      2     20    200   2000  20000
test5.txt  13     3     5      3     30    300   3000  30000
test5.txt  14     4     5      4     40    400   4000  40000
test5.txt  15     5     5      5     50    500   5000  50000


関数の使用事例

スクリプトawk_test.awkを読み込んでout_test.txtに出力する.入力ファイルはないケース.

実行用コマンド

gawk -f awk_test.awk > out_test.txt

関数使用事例のスクリプト (awk_test.awk)

BEGIN{
pi=3.141592654
x= 3.9   ;printf "int(x)    : x=%+8.3f     int(x)=%+d\n",x,int(x)
x=-3.9   ;printf "int(x)    : x=%+8.3f     int(x)=%+d\n",x,int(x)
x= 4.0   ;printf "sqrt(x)   : x=%+8.5f    sqrt(x)=%+8.5f\n",x,sqrt(x)
x= 1.0   ;printf "exp(x)    : x=%+8.5f     exp(x)=%+8.5f\n",x,exp(x)
x=exp(1) ;printf "log(x)    : x=%+8.5f     log(x)=%+8.5f\n",x,log(x)
x=pi     ;printf "sin(x)    : x=%+8.5f     sin(x)=%+8.5f\n",x,sin(x)
x=pi     ;printf "cos(x)    : x=%+8.5f     cos(x)=%+8.5f\n",x,cos(x)
y=1;x=1.7;printf "atan2(y,x): y=%+3.1f x=%+3.1f atan2(y,x)=%+8.5f(%4.1fdeg)\n",y,x,atan2(y, x),atan2(y, x)/pi*180
y=1;x=1.0;printf "atan2(y,x): y=%+3.1f x=%+3.1f atan2(y,x)=%+8.5f(%4.1fdeg)\n",y,x,atan2(y, x),atan2(y, x)/pi*180
printf "rand()    : rand()=%g\n",rand()
printf "rand()    : rand()=%g\n",rand()
srand(5); printf "srand(x)  : srand(5) rand()=%g\n",rand()
srand(5); printf "srand(x)  : srand(5) rand()=%g\n",rand()
print

s1="wantaro";s2="taro"     ;printf "index(s1,s2)   : s1=\"%s\" s2=\"%s\" index(s1,s2)=%d\n",s1,s2,index(s1,s2)
s1="wantaro";s2="xyza"     ;printf "index(s1,s2)   : s1=\"%s\" s2=\"%s\" index(s1,s2)=%d\n",s1,s2,index(s1,s2)
st="wantaro"               ;printf "length(st)     : st=\"%s\" length(st)=%d\n",st,length(st)
st="wantaro"               ;printf "match(st,/*/)  : st=\"%s\" match(st,/taro/)=%d\n",st,match(st,/taro/)
st="wantaro"               ;printf "match(st,/*/)  : st=\"%s\" match(st,/xyza/)=%d\n",st,match(st,/xyza/)
st="wan-ta-ro"             ;printf "split(st,a,\"*\"): st=\"%s\" split(st,a,\"-\")=%d a[1]=\"%s\" a[2]=\"%s\" a[3]=\"%s\"\n",st,split(st,a,"-"),a[1],a[2],a[3]
st=sprintf("pi is %.5f",pi);printf "sprintf(\"*\",x) : pi=%.5f st=sprintf(\"pi is %%.5f\",pi) st=\"%s\"\n",pi,st
s1="wanwantaro";s2="Kon-"  ;printf "sub(/*/,s2,s1) : s1=\"%s\" s2=\"%s\" sub(/wan/,s2,s1)=%d s1=\"%s\"\n",s1,s2,sub(/wan/,s2,s1),s1
s1="wanwantaro";s2="Kon-"  ;printf "gsub(/*/,s2,s1): s1=\"%s\" s2=\"%s\" gsub(/wan/,s2,s1)=%d s1=\"%s\"\n",s1,s2,gsub(/wan/,s2,s1),s1
st="wantaro";i=4;n=2       ;printf "substr(st,i,n) : st=\"%s\" i=%d n=%d substr(st,i,n)=\"%s\"\n",st,i,n,substr(st,i,n)
st="WANTARO"               ;printf "tolower(st)    : st=\"%s\" tolower(st)=\"%s\"\n",st,tolower(st)
st="wantaro"               ;printf "toupper(st)    : st=\"%s\" toupper(st)=\"%s\"\n",st,toupper(st)
print
printf "%s\n","Note) * is something of character or strings."
}

関数使用事例の出力事例

int(x)    : x=  +3.900     int(x)=+3
int(x)    : x=  -3.900     int(x)=-3
sqrt(x)   : x=+4.00000    sqrt(x)=+2.00000
exp(x)    : x=+1.00000     exp(x)=+2.71828
log(x)    : x=+2.71828     log(x)=+1.00000
sin(x)    : x=+3.14159     sin(x)=-0.00000
cos(x)    : x=+3.14159     cos(x)=-1.00000
atan2(y,x): y=+1.0 x=+1.7 atan2(y,x)=+0.53172(30.5deg)
atan2(y,x): y=+1.0 x=+1.0 atan2(y,x)=+0.78540(45.0deg)
rand()    : rand()=0.237788
rand()    : rand()=0.291066
srand(x)  : srand(5) rand()=0.664045
srand(x)  : srand(5) rand()=0.664045

index(s1,s2)   : s1="wantaro" s2="taro" index(s1,s2)=4
index(s1,s2)   : s1="wantaro" s2="xyza" index(s1,s2)=0
length(st)     : st="wantaro" length(st)=7
match(st,/*/)  : st="wantaro" match(st,/taro/)=4
match(st,/*/)  : st="wantaro" match(st,/xyza/)=0
split(st,a,"*"): st="wan-ta-ro" split(st,a,"-")=3 a[1]="wan" a[2]="ta" a[3]="ro"
sprintf("*",x) : pi=3.14159 st=sprintf("pi is %.5f",pi) st="pi is 3.14159"
sub(/*/,s2,s1) : s1="wanwantaro" s2="Kon-" sub(/wan/,s2,s1)=1 s1="Kon-wantaro"
gsub(/*/,s2,s1): s1="wanwantaro" s2="Kon-" gsub(/wan/,s2,s1)=2 s1="Kon-Kon-taro"
substr(st,i,n) : st="wantaro" i=4 n=2 substr(st,i,n)="ta"
tolower(st)    : st="WANTARO" tolower(st)="wantaro"
toupper(st)    : st="wantaro" toupper(st)="WANTARO"

Note) * is something of character or strings.


asort 関数の使用事例

  • asort により文字列の昇順ソートを行う.
  • asort(a,b) とすると,a に元の文字列,b に並び替えられた文字列が格納される.
  • asort(a)とすると a に並び替えられた文字列が格納される.
  • 大文字と小文字が混在する場合,大文字が優先されて並び替えられる.
  • 大文字と小文字の区別をなくしたい場合は,tolower() で小文字に置き換えてソートする.
awk スクリプト実行結果
BEGIN{
a[1]="snow"
a[2]="snow1"
a[3]="snow2"
a[4]="RosyBrown1"
a[5]="RosyBrown2"
a[6]="snow3"
a[7]="LightCoral"
a[8]="IndianRed1"
a[9]="RosyBrown3"
a[10]="IndianRed2"
a[11]="RosyBrown"

n=asort(a,b)
printf "%12s %12s\n","a[i]","b[i]"
for(i=1;i<=n;i++){
printf "%12s %12s\n",a[i],b[i]
}

for(i=1;i<=n;i++){
a[i]=tolower(a[i])
}
print
n=asort(a)
printf "%12s\n","a[i]"
for(i=1;i<=n;i++){
printf "%12s\n",a[i]
}
}
a[i]         b[i]
snow   IndianRed1
snow1   IndianRed2
snow2   LightCoral
RosyBrown1    RosyBrown
RosyBrown2   RosyBrown1
snow3   RosyBrown2
LightCoral   RosyBrown3
IndianRed1         snow
RosyBrown3        snow1
IndianRed2        snow2
RosyBrown        snow3

a[i]
indianred1
indianred2
lightcoral
rosybrown
rosybrown1
rosybrown2
rosybrown3
snow
snow1
snow2
snow3






ファイルに処理結果を出力

事例 (1)

gawk "BEGIN{pi=3.141592654;for(i=-89;i<=270;i++){print 0.3*cos(i/180*pi)-7.0,1.5*sin(i/180*pi)+52.4}}" > _temp.txt

この事例では,中心(-7.0,52.4),短半径 0.3,長半径 1.5 の楕円の座標をファイル _temp.txt に出力している. データ区切りはブランク.

事例 (2)

gawk "{if(NR==1){sub(/#/,\"\",$0);printf \"0.3 14.5 12 0 0 ML %%s\n\",$0}}" %inp_1% > _val.txt
  • 変数 inp_1 にセットされた入力ファイルの行数が 1 だったら,「0.3 14.5 12 0 0 ML %%s」という文字列を出力ファイル _val.txt に書き出す.
  • %sには,sub 関数により処理された入力ファイル1行目の全文字列$0が当てはめられる.
  • sub(/#/,\"\",$0)は,文字列$0の中の「#」という文字を削除する処理を行う.

事例 (3)

gawk "{if(0<index($0,\""<"h2">"\")) print $0}" org_f90.html > test1_f90.txt
  • HTML ファイルの見出しを検索してファイルに書き出す.
  • 不等号はコマンドプロンプトのリダイレクト記号なので, "<" や ">" のように double-quotation で囲む.
  • double-quotation 自体の出力には,前に\マークを加える.(\")
  • double-quotation だらけで見づらいので注意が必要!


ソートされたフォント名一覧を作成する

dir c:\windows\Fonts\*.ttf > fname.txt
dir c:\windows\Fonts\*.ttc >> fname.txt
gawk "{if(index($1,\"/\")==5)print $4}" fname.txt > fname1.txt
gawk "{print tolower($0),$0}" fname1.txt > fname2.txt
gawk "{str[NR]=$0}END{n=asort(str);for(i=1;i<=n;i++)print str[i]}" fname2.txt > fname3.txt
gawk "{print $2}" fname3.txt > inp_fname.txt


GMT の psxy にデータを渡す

事例 (1)

gawk "BEGIN{FS=\",\"}{if(568<=NR&&NR<=610)print $2,$5*1000}" %inp_4% | psxy -R -J -B -W5 -P -O -K >> %fig_out%

この事例では,変数 inp_4 にセットされているファイルから gawk でデータを読み取り,処理結果を GMT の psxy に渡している. awk での処理内容は,以下のとおり.

  • 入力データファイルのデータ区切り文字を comma「,」にセット.
  • 入力ファイルの行数 568 から 610 までの数値並びのうち,第 2 列を x 値,第 5 列を1000倍したものを y 値として psxy に渡す.

事例 (2)

gawk "BEGIN{FS=\",\"}{if(3<=NR)print NR-2.5,$7}" dat_inp_climate.csv | psxy -R -J -Sb1u -W1 -G0/255/255 -B -K -O >> %fig_out%
  • 入力データファイルのデータ区切り文字を comma「,」にセット.
  • 入力ファイルの行数が 3以上になったら,x 値を入力ファイルの行数マイナス 2.5 (NR-2.5) 第 7 列を y 値として psxy に渡す.


GMT の pstext にデータを渡す

gawk "{if(NR==35) printf \"9.5 5.5 12 0 0 MR %%gm@+3@+/s\",$2}" _temp0.txt | pstext -R -J -Gred -P -O -K >> %fig_out%
  • 入力ファイルの行数が 35 になったら,「9.5 5.5 12 0 0 MR %%gm@+3@+/s」という文字列を pstext に渡す.
  • %gには,入力ファイルの2列目の数値が当てはめられる.


pic
inserted by FC2 system