ログとかコマンドの出力から、該当行だけ抜き出して sed で編集する。 みたいなことが必要になることがあります。
無理やりな例だと、jail の etc 以下を比較してみましょう。
$ sudo diff -rq /usr/jails/newjail/etc /usr/jails/m/etc | grep "^Only in"
片方にしかないファイルの一覧を出します。
これと同じことが sed
でもできます。
$ sudo diff -rq /usr/jails/newjail/etc /usr/jails/m/etc | sed -n -e '/^Only in / p'
-n
は各行の出力を原則無しにする引数です。そうすると何も出力されなくなるので、
正規表現の末尾に p
コマンドを追加して、ヒットした行だけ表示します。
この辺の文法は awk
に似ていて、-e
の式は 条件文 + コマンド
の形に本来はなります。
/^Only in/
が正規表現のマッチングで、これがヒットした場合に、p
コマンド(出力)を実行します。
grep
と同じことができるなら grep
でいいじゃん?という話でもありますが、
まず grep
と sed
は採用している正規表現の文法が微妙に違うので、
sed
にしかない表記をしたい場合に役立ちます。
また、sed
の -e
は複数連続して記述できるので、
$ sudo diff -rq /usr/jails/newjail/etc /usr/jails/m/etc | sed -n -e 's/: /\//' -e '/^Only in / p'
こんな風に、区切り文字を置き換えてから検索、みたいなのが sed
の 1 プロセスで終わります。
つまり少しだけコンピュータに優しい命令になります。
さらに、正規表現の match ではなく、置換も条件文として使えるので、
$ sudo diff -rq /usr/jails/newjail/etc /usr/jails/m/etc | sed -n -e 's/: /\//' -e 's/^Only in // p'
こうやって、Only in を削除してから出力。みたいなこともできます。
複数の -e
はそれぞれ1つのコマンドなので、;
で区切って複数命令渡すこともできます。
$ sudo diff -rq /usr/jails/newjail/etc /usr/jails/m/etc | sed -n -e 's/: /\//; s/^Only in // p'
ここで、:
を置き換える命令はそれ単独で動く命令なので、
Only in
にマッチしようがしまいが置換されますし、
:
にマッチしなくても、Only in
にマッチすれば出力対象となります。
シェル曲芸的な感じだと、こんなこともできます。
$ cat maillog | sed -n -e '/postfix\/smtpd/ s/^.*connect from \(.*\)\[.*$/\1/p' -e '/ pop3-login: / s/^.*user=<\([^>]*\)>.*$/\1/p'
smtpd のログなら接続元を表示し、pop3 でのログインならユーザ ID を表示する。 grep を別で実行すると複数命令に分かれますし、時系列順が壊れてしまうので、 まぁこういうのが必要になることは……なさそう?