ここ数回にわたりフィルタコマンドを取り上げている本連載に合わせるかのように、先日「GNU sed」の最新の安定版となる「GNU sed 4.3」が公開された。現在、最も使われているであろうGNU sedのバージョンは、2012年に公開された4.2.2であり、4年という開発期間を経て久々に新しい安定版がリリースされたことになる。

sedコマンドは、既に枯れたコマンドと言ってよいと思う。広く利用され、機能もよく知られており、使い方ももう変わらない。こういったコマンドで新しい安定版がリリースされるというのはあまりないことなので、ちょうど連載で取り上げているこのタイミングで新しいバージョンに出会えたのは良かったと思う。

今回はちょっと趣向を変えて、GNU sed 4.3での主な変更点を取り上げて解説したい。新バージョンでは、なかなか興味深い改善が盛り込まれている。

GNU sed 4.3の注目ポイント

GNU sed 4.3で最も注目したいのは、次のポイントだ。

  • 正規表現マッチング処理をおよそ10倍に高速化
  • アンロックI/Oが機能する場合にはアンロックI/Oを使うようになり、この条件で動作する時にはI/Oオペレーションの高速化が可能

「高速化」というのは、ソフトウェアのアップグレード理由や購入理由、移行理由として最も大きなパワーを持っている。IT業界において「速いは正義」なのだ。これだけで、GNU sed 4.3が使いたくなってくる。

次に大きな改善としては、バグ修正が挙げられる。今回のバージョンでは、少々複雑な指定をした場合、想定したように正規表現が機能していなかったところが修正されていたり、不適切なマルチバイトシーケンスに対する処理がよりうまく動作するように工夫が行われたりしている。

これら以外にも、古い機能の削除やアーカイブ時の圧縮に「gzip」ではなく「xz」が使われるようになるなど、細かい変更が加えられた。

最新版の公開アナウンスには、修正されたバグの動作を確認するサンプルコマンドが掲載されているが、動作としてもバグとしても面白いのでここで取り上げてみようと思う。例えば、GNU sed 4.2.2で「seq 6 | gsed ‘2,4d;2,3s/^/x/;3,4s/^/y/’」を実行すると次のような挙動を示すのだが、これは動作としては間違っている。


% seq 6 | gsed '2,4d;2,3s/^/x/;3,4s/^/y/'
1
yx5
6
%

これをBSD sedやGNU sed 4.3で実行すると、次のようになる。


% seq 6 | sed '2,4d;2,3s/^/x/;3,4s/^/y/'
1
5
6
%

これが、正しい動作だ。

コマンドの指定について、順番に説明しよう。まず、「seq 6」という指定は、次のように動作する。


% seq 6
1
2
3
4
5
6
%

続くsedの「2,4d」という指定は、「2行目と4行目までを削除せよ」という命令だ。seqで出力されているデータの2行目、3行目、4行目が削除されることになるから、残りは1行目、5行目、6行目ということになる。sedはこのように範囲を指定した削除処理に使われることも多い。

その次の「2,3s/^/x」と「3,4s/^/y」は、「2行目と3行目に対して置換処理を行って行頭をxに変換、3行目と4行目に対して置換処理を行って行頭をyに変換せよ」ということだ。実際には、2行目から4行目までは削除されているので何の処理も発生しないのが正解なのだが、GNU sed 4.2.2では5行目が処理されてしまっている。

今回は、GNU sed 4.2.2のバグが4年を経て修正されたわけだが、バージョンアップで機能を追加することが多いタイプのコマンドでは、リグレッションが発生することがある(もちろん、テストコードを充実させてリグレッションの発生を防止する開発体制になっているものもある)。

逆に、BSD sedのように一度挙動を定めたら以降は変えないタイプのコマンドでは、そうしたバグは発生しにくい。一長一短なのだが、バージョンが上がるとバグが発生して挙動が変わることもあるというのは知っておいたほうがよいだろう。

バグが発生して動作が変わるのはとても困るわけだが、こうしたバグは頻度の高い使われ方では起こらないことが多い。つまり、一般的な指定を使うようにしていれば、バグに遭遇する可能性を下げられるわけだ。この辺りの感覚は、上級エンジニアは何となく身につけていて、無意識のうちに問題の発生しにくいスクリプトを書いていたりする。こうした一種の「危機察知能力」は、本連載の読者もぜひ身につけてもらいたい。