フィルタリングによるデータの抽出は、サーバ管理者がよく行う作業の1つだ。前回まで、フィルタコマンドとして「grep(1)」を取り上げてきた。grep(1)を使うとテキストデータから欲しいデータを含む行のみを簡単に取り出せる。今回からは、同じくデータ抽出に使えるコマンドとして、「sed(1)」を取り上げようと思う。

ストリームエディタ sed

前回まで、「grep(1)」を中心にフィルタコマンドの使い方について紹介してきた。テキストを処理するフィルタコマンドとしては、「sed(1)」もよく使われている。マニュアルを引くと、sedには「ストリームエディタ」とか「テキストのフィルタや変換処理を実施するストリームエディタ」といった説明がある。

ストリームエディタという呼び方は、「ed(1)」というテキストエディタを使っていたユーザであればピンとくるかもしれない。「Vi」や「Vim」を使ったことがあるなら、コマンドモードで入力する「:」以降のアレを取り出したコマンド、と考えると想像しやすいとだろう。要するに、それまでed(1)というエディタで使っていた機能の1つを抜き出し、単体のコマンドとして使えるようにしたものがsed(1)だ。

sedを使うと、指定に一致したテキストに対し、各種の変換機能を適用することができる。利用できる機能は、テキストの選択・出力・追加・削除・置換などだ。なかでもよく使うのは、テキストの置換処理だろう。まず、grep(1)で必要な文字列を含む行を取り出し、sed(1)でそのデータを変換するといった具合だ。

例えば、前回の記事を参照されたい)。


% cat doc |
> gsed 's/^## \(.*\)$/\1\n##/' |
> grep -E -B 1 '(^=+$)|(^-+$)|(^#+$)' |
> grep -v -- '^--$' |
> tail -r |
> tr '\n' '\t' |
> gsed -e 's/##\t/  o /g' -e 's/--*\t/ - /g' -e 's/==*\t//g' |
> tr '\t' '\n' |
> tail -r
TTT COMMANDS
 - Download
 - Installation
  o required packages installation
  o build and install
%

このコマンドでは、sed(1)が出力を整形するためのコマンドとして使われている(「gsed(1)」については後ほど説明するが、sed(1)と同じようなものだと思っておいてもらえればと思う)。具体的には、1つ目のsedで小々見出しを他の見出しと同じように処理できるようにフォーマットを変更し、2つ目のsedで出力用に内容を整形している。

sed(1)にはこのほかにも機能が用意されているが、よく使われるのは置換処理だ。「置換と言えばsed。sedと言えば置換」という印象がある。

sed(1)の置換処理を使いこなすには、「後方参照」という機能を理解しなければならない。後方参照を使わなくても同じことはできるが、それはとても面倒な作業になる。

今回は触れる程度にしておくが、以下の処理では後方参照が使われている。


's/^## \(.*\)$/\1\n##/'

最終的にこの指定を読んで意味がわかるようになれば、sed(1)の利用スキルとしては充分だ。逆に、後方参照が使えないとかなり苦労することになるので、まずはこの指定を解読できるようになることを目指してほしい。

複数存在するsedの実装系

sedコマンドは、もともとVersion 7 AT&T UNIX向けに追加されたコマンドだとされているが、現在ではいくつかの実装系が存在している。sedコマンドには、IEEE Std 1003.2 (POSIX.2)の機能を実装していることが望ましいとされているので、この機能だけを使っているのであればどの実装系を使っても問題ないことが多い。

逆に、特定の実装系の拡張機能を使っていると、同じ「sed」という名前のコマンドであっても指定してある内容が思ったとおりに機能しないケースがある。

例えば、Linuxディストリビューションでは多くの場合、「GNU sed」がsed(1)の実装系としてインストールされている。一方、Macや*BSDでは「BSD sed」と呼ばれる実装系がインストールされていることが多い。GNU sedの拡張機能を使うように組まれたスクリプトになっていると、Macや*BSDで使う際には指定を変更するか、明示的にGNU sedを使うように変更する必要がある。

幸い、Macや*BSDではGNU sedはパッケージ管理システムから「gsed」としてインストールできるので、GNU sedをインストールしてsedの部分をgsedに置き変えればそのまま利用できる。上記サンプルはgsedというコマンド名になっていたわけだが、つまりそういうことだ。この方法ならば、Macでも同じスクリプトが使えるので便利だ。

GNU sedは、拡張機能として置換後の文字列に改行の指定を含めることができる。実際のところ、これが結構便利だったりする。POSIX.2準拠のsed機能だけでも似たようなことはできるが、この部分はGNU sedのほうがシンプルに書けて扱いやすい。もし、「参考書やググった内容をベースにsedコマンドを使ってみたものの動かない(例えば、Linuxのsedの説明をMacで使ってみたけどうまくいかないとか)」といった場合、使っている実装系が違うからかも知れないと疑ってみてほしい。

次回から数回は、このsed(1)コマンドについてもう少し掘り下げて紹介しようと思う。実装の違いもちょいちょい説明しようと思うので参考にしていただきたい。