3 節で見たように、
<title>
</title> 部分は複数行でできているようです。
このサンプルでは 3 行ですが、
実際にはもっと長かったり短かったりするかもしれません。
<title>, </title> タグ自体も
サンプルではそれらが単独の行になっていますが、
実際には <title> の次に改行なしですぐに内容の文が続いたり、
</title> の後ろに何らかの文字が続いているかもしれません。
一方で AWK は基本的に行単位のフィルタで、 入力を 1 行ずつ読み込んで処理する形になっています。 よって、このように処理の単位が複数行である場合は、 以下のような 2 種類の処理の方法が考えられます。
getline は新たな行を取得するときに使います。
これらを AWK の (疑似) コードで書くとそれぞれ以下のようになります。
($0 ~ /<title>/){
N=0
h[++N]=$0
while($0 !~ /<\/title>/){
getline
h[++N]=$0
}
# h[1] ~ h[N] までに保存されているのでその処理をする
}
($0 ~ /<title>/){ flag=1; N=0 }
(flag==1){
h[++N]=$0
if($0 ~ /<\/title>/){
flag=0
# h[1] ~ h[N] までに保存されているのでその処理をする
}
}
現在の入力行全体は $0 で、
文字列が正規表現にマッチするかどうかは ~, !~ で調べます。
文字列 ~ /正規表現/ : 文字列が正規表現にマッチすれば真
文字列 !~ /正規表現/ : 文字列が正規表現にマッチしなければ真
/ / で囲んで指定します。
正規表現のパターン内に / を書く場合は、
区切り記号と区別するために \ をつけて \/ と書きます
(エスケープ)。
上のサンプルでは、配列に各行を保存していますが、または <title>
</title> を一つの文字列として保存する手もあります。
その場合は、上の ``h[++N]=$0'' の代わりに、例えば ``str = str $0'' のようにします。
AWK では 2 つの文字列を並べると、それで文字列の連結を意味します。
また、getline を使う場合は、 万が一 </title> を含む行が見つからなかった場合を考えて (その場合最後の行まで一気に取得してしまう)、 単なる getline の代わりに
if(getline<=0){ errorexit=1; exit }
のようにしておくといいかもしれません。
exit は、入力の読み込みをやめ、
END ブロックがあればそこにジャンプするだけなので、
その前に errorexit などのような変数 (変数名は何でも構いません)
をセットすることで、END ブロックの先頭に
END{
if(errorexit){
printf "エラー発生 (code = %d)\n",errorexit > "/dev/stderr"
exit
}
....
と書いておけば END ブロックの他の処理を実行せずに
エラー終了することができます。
なお、この printf の後ろについている「> "/dev/stderr"」は
本来は Unix に由来する記法で、
標準エラー出力への出力を行うための書き方です。
こう書けば AWK の出力をファイルなどにリダイレクトしても、
この出力はリダイレクトされずに画面に表示されます。