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

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

Line 1.
Line 2.
Line 3. test
Line 4.
Line 5.

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

$ sed -ne '/test/,+1p' sample.txt
Line 3. test
Line 4.

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

$ sed -n "$((`sed -n '/test/=' sample.txt` - 1)),+2p" sample.txt
Line 2.
Line 3. test
Line 4.

コマンドを単純化して見ると、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行分を削除したければ、次のようになる。「"」はエスケープせずそのまま書けばよい。

$ vartest="3. test"
$ echo "$vartest"
3. test
$ sed -i "$((`sed -n "/${vartest}/=" sample.txt | head -1` - 1)),+2d" sample.txt

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

$ grep -A1 -B1 test sample.txt
Line 2.
Line 3. test
Line 4.

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

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

$ sed "$((`sed -n '/test/=' sample.txt` - 1))i\Inserted." sample.txt
Line 1.
Inserted.
Line 2.
Line 3. test
Line 4.
Line 5.

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

$ sed -n '/test/=' sample.txt
3

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

$ grep -n test sample.txt
3:Line 3. test