ワンライナー!ワンライナー!
みんな大好きワンライナー。
たくさん使いこなせるとイケメンですね^^
複数行のほうがカッコイイぜという変態の方は大変申し訳ありませんが対象外となります。
普通のコマンドはいくつかの引数(オプション等)を覚えればおしまいですが、sedはそう簡単にはいきません。
sedは、ストリームエディタ(Stream EDitor)の略でテキスト処理を行うプログラムです。文字列を置換したりする際によく使いますね。
sedの書式は、vimなんかでもよく使ったりするので積極的に覚えましょう。
sed書式
# スクリプトを直接指定
$ sed -e 'スクリプト'
# スクリプトが記述されているファイルを指定
$ sed -f 'スクリプトファイル名'
# 表示を抑制(明示的にスクリプト中でpをすれば表示も可能)
$ sed -n 'スクリプト'
# 拡張正規表現を使ったスクリプトを記述
$ sed -r '正規表現を使ったスクリプト'
スクリプト部分はざっくり言うと以下の様な構成です
「スクリプト=範囲指定+コマンド」
sed使用例
以下BSD sed, GNU sedで動作確認しています。
基本的な文字列処理
マッチした文字列を置換する
$ echo 'before text' | sed 's/before/after/'
after text
マッチした文字列をすべて置換する
$ echo 'before before before text' | sed 's/before/after/g'
after after after text
複数の文字列を一度に置換する
# before1→afterA、before2→afterBに置換
$ echo 'before1before2' | sed 's/before1/afterA/;s/before2/afterB/'
afterAafterB
置換時にマッチしたキーワードを再利用する
# githubというマッチしたキーワードを&で再利用
$ echo 'github' | sed 's/github/I like &./'
I like github.
1文字づつ置換する
# eとoをEとOに置換する
$ echo -e "book\nball\norange\nmelon\npen\nmouse" | sed 'y/eo/EO/'
bOOk
ball
OrangE
mElOn
pEn
mOusE
範囲を限定したテキスト処理
最初にマッチしたものだけ置換する
# 1行目からccccのある行までを探索し、ccccをeeeeに置換
# sの前には1,3とか数値だけを指定してもいい
$ echo -e "aaaa\nbbbb\ncccc\ndddd\ncccc" | sed '1,/cccc/s/cccc/eeee/'
aaaa
bbbb
eeee # 最初にマッチしたので置換されている
dddd
cccc # 最初のマッチじゃないため置換されない
指定範囲の行を削除する
# aaaaからccccまでの範囲を削除
$ echo -e "aaaa\nbbbb\ncccc\ndddd" | sed '/aaaa/,/cccc/d'
dddd
# 1行目から2行目までを削除する
$ echo -e "aaaa\nbbbb\ncccc\ndddd" | sed '1,2d'
cccc
dddd
# 空行または#で始まるコメント行削除
$ echo -e '1:one\n2:two\n\n# 3:three\n4:four' | sed '/^$/,/^#/d'
1:one
2:two
4:four
指定範囲の行を表示する
# aaaaからccccまでの範囲を表示
$ echo -e "aaaa\nbbbb\ncccc\ndddd" | sed -n '/aaaa/,/cccc/p'
aaaa
bbbb
cccc
# 3行目から最後の行までの範囲を表示
$ echo -e "aaaa\nbbbb\ncccc\ndddd" | sed -n '3,$p'
cccc
dddd
指定行以外を表示する
# 2行目以外を表示
$ echo -e "aaaa\nbbbb\ncccc\ndddd" | sed -n '2!p'
bbbb
cccc
ファイル内の指定行のみ出力
# file1.txtの10行目を取得
$ sed -n 10p file1.txt
指定行にデータを挿入
# 1行目に######を挿入(iはマッチ行の手前)
# echo -e "aaaa\nbbbb\ncccc\ndddd" | sed '1i\######'
######
aaaa
bbbb
cccc
dddd
# 最終行に######を挿入(aはマッチ行の後)
# echo -e "aaaa\nbbbb\ncccc\ndddd" | sed '$a\######'
aaaa
bbbb
cccc
dddd
######
正規表現を使った文字列置換
実際にコーディングしたり設定を書き換えたりするには正規表現が必須ですね。
マッチした文字列の一部を再利用する
()でくくれば、置換後文字列で\1,\2,\3・・・のように部分的に再利用できます。
ただし()はそれぞれ\(,\)とエスケープしてやる必要があります。
# phpのテンプレコードをruby(erb)コードに変換する
$ echo -e "<?php echo 'hogehoge'; ?>" | sed 's/<?php echo \(.*\); ?>/<%= \1 %>/'
<%= 'hogehoge' %>
最短マッチさせる
# <a href="http://www.yahoo.co.jp/" class="others">Yahoo!</a>からURL抽出する
# (NG例)不用意に.*を使うと意図せぬマッチングになってしまう
$ echo -e '<a href="http://www.yahoo.co.jp/" class="others">Yahoo!</a>' | sed 's/<a href="\(.*\)".*$/\1/'
http://www.yahoo.co.jp/" class="others
# (OK例)最短マッチ ([^"]*で"以外のすべての文字の繰り返しとして指定)
$ echo -e '<a href="http://www.yahoo.co.jp/" class="others">Yahoo!</a>' | sed 's/<a href="\([^"]*\)".*$/\1/'
http://www.yahoo.co.jp/
応用例
ログ監視
指定日・指定時間のaccess_logを見る
※apacheのログ書式に応じてフォーマットを見なおしてください
# 02/May/2014を含む行を表示
$ cat /var/log/apache2/access_log | sed -n '/02\/May\/2014/p'
# 02/May/2014の22時台の行を表示
$ cat /var/log/apache2/access_log | sed -n '/02\/May\/2014:22/,/02\/May\/2014:23/p
root以外のsyslogを見る
grep -vでもいいんですけどね・・・。
# rootを含まない行を表示
$ cat /var/log/syslog | sed -n '/root/!p'
Web解析
WebページからURL一覧抽出
わざわざプログラム組まなくてもできます。
# hrefの中身だけを抽出してリストアップ
# 1行に2つ以上aタグがある場合は対応できていません。
$ curl http://b.hatena.ne.jp/hotentry/it | sed -n 's/^.*href="\([^"]*\)".*$/\1/p'
Webページから記事タイトルを抽出してリストアップ
# 上とは別の例としてegrepでaタグに絞込み
# その後sedでタグを除去し、行頭のスペースを除去
$ curl http://b.hatena.ne.jp/hotentry/it | egrep "<a.*entry-link" | sed 's/<[^>]*>//g;s/ //g'