ファイル内のある条件を満たすある行を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