- あるテキストの入力ファイルがあり、中身は次のようなかんじ
Mapping JP { ... } Mapping AU { ... } Mapping JP { ... } Mapping XX {という行ではじまり}でおわるのが一つのブロック。- この中で
Mapping JP { ... }というブロックをすべて抜きだしたい
sedで簡単にできますよ。」こんなかんじで
% sed -ne '/^Mapping JP {/,/^}/p' datafile
- defaultでは出力しない(
-nオプション) Mapping JP {ではじまる行から、}ではじまる行までは出力する(/start/,/end/という範囲でpコマンド)
しばらくして…
「実はフォーマットがちょっと違ってました。これならどうなりますか?」
- テキストの入力ファイルがあり、中身は次のようなかんじ
Mapping { id: foo country: "JP" ... } Mapping { id: bar country: "AU" ... } Mapping { id: baz country: "JP" ... } Mapping {という行ではじまり}でおわるのが一つのブロック。- この中で
country: "JP"を含むブロックをすべて抜きだしたい
sedだとちょっと面倒だなあ。hold spaceかな」といっていたら
「
perlでmultiline regexp使ったら簡単じゃないですか?」で、でてきたのがこれ
% perl -n0e 'print "$_\n" for /^Mapping {[^}]+country: "JP"[^}]+}/gms'\
datafile
sedやawkのようにループして処理する(-nオプション)- record separetorとしてnull文字を設定する(
-0オプション)。つまりファイルを全部一気に読む - ファイル全体に対して
^Mapping {[^}]+"JP"[^}]+}にマッチする部分をそれぞれ出力する。gでglobal matching、mでmultilineとして処理する(^は文字列の先頭にマッチするのでは行頭にマッチするようになる)、sでsinglelineとして処理する(.なども改行文字にもマッチするようになる)
sedだとこう
% sed -ne '/^Mapping {/,/^}/H;/^}/{s///;x;/country: "JP"/p}' datafile
- defaultで出力しない(
-nオプション) Mapping {ではじまる行から}ではじまる行までhold spaceにためていく。(/start/,/end/という範囲でHコマンド)}ではじまる行で次の処理を行う({...}で処理するコマンドをグルーピングs///でまず現在の行(})を消す- hold spaceをpattern spaceに戻す(
xコマンド) - 戻してきたpattern spaceで
country: "JP"があれば出力(pコマンド)
s///するのを忘れていて、無駄な}がでちゃうなあというあたりでちょっとはまっていた。でもperl版より短い。ちなみに世の中には
sgrepとかいうのがあって、次のように使えるっぽい
% sgrep 'outer("Mapping {" .. "}" containing ("country: \"JP\""))'\
datafile
Mapping {から}の中にcountry: "JP"が含まれていたらそのブロック全体を出力
No comments:
Post a Comment