- あるテキストの入力ファイルがあり、中身は次のようなかんじ
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