sedやgrepで、ある行のn行前から処理対象にする

2016/11/21

ファイル内のある条件を満たすある行をsedで処理したいときは、正規表現等を使用すればよい。しかしその行のn行前から処理する方法は少し工夫が必要となる。

次のファイル(sample.txt)があるとする。

testを含む行から1行を表示したければ、-nオプションと現在のパターンスペースを出力するpコマンドを使用して、次のようにすればよい。

それではtestを含む行の1行前から計3行を表示したければどうするか。
結論としては、次のコマンドで実行できる。

コマンドを単純化して見ると、sed -n "アドレス,+2p" sample.txtで成り立っており、「アドレス」の部分のみ少し複雑、かつ肝となっている。
「アドレス」部分はまず、sed -n '/test/=' sample.txtでsample.txt内でtestという条件と一致する行数を=コマンドで取得している。今回だと、このコマンドは3を返す。
ゆえに$((3 - 1)) = 2となり、3行目の1行前、つまり2行目が得られる。
sed -n "2,+2p" sample.txtが最終的に実行されるコマンドなので、2行目から+2行分(つまり計3行)を表示することになる。

変数を使うなど場合で「"」が入れ子になる時、\"にすると、動かないので注意。
例えば、次のように、vartest変数がはじめに現れる行の1行前から+2行分を削除したければ、次のようになる。「"」はエスケープせずそのまま書けばよい。

表示だけならば、grepを使用した方が簡潔に書ける。

-Aオプションで合致した行の後の行数を、-Bオプションで前の行数を指定して表示できる。

しかし、sedを使う方が表示だけでなく編集にも応用が利くので、sedを使用する方法も覚えておきたい。
もしtestを含む行の1行前の行の上(つまりLine 2.の上)に行を追加したいとなれば、同じ構造を用いて、iコマンドで実行できる。

今回アドレス部分で使用したsedの=コマンドは、アドレスに合致する行番号を返すので、-nオプションと併せて使うことで、マッチした行数だけを取得できる。

またしてもgrepとの比較になるが、grepの-nオプション(--line-number)でも同様のことができる。しかしこちらは余計な出力がついてくるので、行数だけを取得した場合は、grepよりsedを使用した方がいいだろう。

-Linux
-,