awkで複数行処理を行う

awk は基本的に1行ずつ処理をするのだけども、XMLを見るときなんかはどうしても複数行処理したくなることがある。

そんなときに便利な関数が「getline」だ。

getline を引数なしで呼び出すと、今処理している行の次の1行読み込んで、$0とかNFとかに新しい値をセットする。

(前の$0とか消えてしまうけども、それが嫌ならgetlineに引数を渡すと、そこに格納してくれるようだ)

 

実際に試してみた方が早いと思うので、以下のようなXMLファイルから、特定の値をとりだすことをやってみる。

 

[root@localhost ~]# cat example.xml
<?xml version="1.0">
<gloup name="gloup1">
 <menber>member1</menber>
 <menber>member2</menber>
 <menber>member3</menber>
</gloup>

<gloup name="gloup2">
 <menber>memberA</menber>
 <menber>memberB</menber>
 <menber>memberC</menber>
</gloup>

<gloup name="gloup3">
 <menber>memberX</menber>
 <menber>memberY</menber>
 <menber>memberB</menber>
</gloup>
[root@localhost ~]#

 

gloup1 と gloup3のmemberだけ取り出したい、というときに、getlineを使うと比較的簡単に処理が出来る。

awk '$1 == "<gloup" && $2 ~ /gloup(1|3)/ { print $2 ; while ( getline ) { if ($0 ~ /<\/gloup>/ ) { break } else { print $0 } } }' example.xml

while とか if は一般的なプログラム言語とだいたい同じ動きをする。

ここでは、gloup要素を発見すると、2カラム目を参照し、それがgloup1かgloup3だった時に、</gloup>が来るまで行を出力している。

実行結果はこんな感じ。

[root@localhost ~]# cat example.xml
<?xml version="1.0">
<gloup name="gloup1">
 <menber>member1</menber>
 <menber>member2</menber>
 <menber>member3</menber>
</gloup>

<gloup name="gloup2">
 <menber>memberA</menber>
 <menber>memberB</menber>
 <menber>memberC</menber>
</gloup>

<gloup name="gloup3">
 <menber>memberX</menber>
 <menber>memberY</menber>
 <menber>memberB</menber>
</gloup>
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# awk '$1 == "<gloup" && $2 ~ /gloup(1|3)/ { print $2 ; while ( getline ) { if ($0 ~ /<\/gloup>/ ) { break } else { print $0 } } }' example.xml
name="gloup1">
 <menber>member1</menber>
 <menber>member2</menber>
 <menber>member3</menber>
name="gloup3">
 <menber>memberX</menber>
 <menber>memberY</menber>
 <menber>memberB</menber>
[root@localhost ~]#

複数の機器でミドルウェアのセットアップとかした時、いちいち結果をGUIで確認すると時間がかかって仕方がない。

直接XMLを見るときに、こんな感じで該当箇所だけ抜き出せると良い感じ。

(sub 関数とか上手く使えば出力結果を綺麗に整形できると思うけども、今回は割愛)