2013年8月21日水曜日

読書感想文: Software Design 2013年9月号「sedの詳細と利用法」

Software Design 2013年9月号の第1特集が、「sed/AWK再入門」という非常に魅力的なものだったので、買ってきました。特集の一部として、「sedの詳細と利用法」というsedに特化した内容で一章分割り当てられています。いちsedユーザーとして、とても楽しみでした。別にsed好きだからというわけではありませんが、読んでいてこの章には思うところがふつふつと湧いて来たので、せっかくなので感想など書いてみます。ちょうど読書感想文の季節ですし。感想と言っても、身銭を切って記事を買った人間としての、記事に対する不満がほとんどです。

誰得なの?
いったい誰得の記事なのか全くわかりませんでした。感想はこれに尽きます。要は、入門者向けとしても、sed知ってる人向けとしても、ものすごくビミョーな風に感じました。おそらく記事の方向性としては、入門者向けに、これからsedを覚えてバリバリ使ってこうぜ、というような方針があるのだろうと思います。「s」コマンドに多くの紙幅を割いていることからも、それはわかります。その割にsedの重要な基礎的な部分がすっ飛ばされています。たとえば、sedに指示を出すにあたって最低限知っていなければならない、sedの編集サイクルに関する説明がありません。これは基礎中の基礎です。入力、コマンド処理、出力、それらがどういう段取りで行われるのかの理解がなければ、sedを操れるようにはなれないでしょうし、それどころかmanページすら理解できないと思います。その一方で「b」「t」「:」の制御系コマンドなど、編集サイクルの理解がないと使いこなせないような、一定レベル以上のユーザー向けのコマンドに紙面が割かれています。

他には、sedを使うのに必須の知識となる「-n」オプションの説明があっさりしすぎています。「置換された行だけ表示したい場合は、sedを「-n」オプション付きで起動し、標準出力を抑制します。」とだけ説明があります。記事中でのサンプルにとってはそのとおりなのですが、「-n」オプションは置換された行だけ表示したい場合に使うためにあるオプションではありません。「-n」のちゃんとした説明が無いということは、コマンドラインツールとしてあまりにも重要な入出力に関わるちゃんとした説明が無いということです。「-n」オプションと「p」コマンドは、sedの出力制御の要となる基礎中の基礎ですが、特に「p」コマンド(フラグではなく)の説明はほとんどなく、一体誰にsedの何を伝えたいのか理解に苦しみました。「w」コマンドみたいなリダイレクトでどうにでもなるコマンドに紙面を割くくらいなら、入出力の説明のために割いた方が懸命でしょう。もし、この記事の対象が、「p」みたいな基本的なコマンドはすでに知っている人向けのものだというのであれば、なぜ「s」というもっと基本的なコマンドを長々と説明しているのか疑問です。

ちなみに、入門者向けの内容からはちょっと外れますが、「-n」はsedスクリプトの移植性を高めるためのポイントでもあります。移植性に考慮したシェルスクリプト中でsedを使う場合には、「-n」は極力使用した方が良いのです。実は、sedの自動出力(posixで言うところのデフォルト出力、自動出力はGNUの用語)は、実装によってその出力契機がまちまちです。つまり、自動出力を抑制していない場合は環境によって思わぬ挙動となってしまうことがあるので、それを防ぐために-nを常に指定しておくというのが、sedをシェルスクリプト中で使うときのTipsとしてあります。例えば、IEEE Std 1003.1, 2004 Editionのsed仕様には、こういう記述があります。
The treatment of the p flag to the s command differs between System V and BSD-based systems when the default output is suppressed. In the two examples:

echo a | sed    's/a/A/p'
echo a | sed -n 's/a/A/p'

this volume of IEEE Std 1003.1-2001, BSD, System V documentation, and the SVID indicate that the first example should write two lines with A, whereas the second should write one. Some System V systems write the A only once in both examples because the p flag is ignored if the -n option is not specified.

自動出力の挙動の違いについては、さらにGNU sedを例にとると、
$ echo a | sed N
a
$ echo a | sed --posix N
$
という、わかりやすい違いが確認できます。これについては、GNU sedのマニュアルにも、GNU sedと他の多くの実装とでは、自動出力を抑制していない場合に、挙動が異なるという点が明記されています。
Most versions of sed exit without printing anything when the N command is issued on the last line of a file. GNU sed prints pattern space before exiting unless of course the -n command switch has been specified. This choice is by design.

不可解な挙動に悩まされたくなければ、極力-nを付けるようにするのが懸命なのです。赤子泣いても-n取るなと、昔の人も言いました。「-n」オプションは、移植性の話はともかくとしても、出力制御という意味でsed操作の超重要な部分なので、-nの説明はちゃんとした方が良いと思います。そのためにも、入出力とパターンスペースなど、基本的な編集サイクルの説明が必要になるわけです。

あと、細かいところですが個人的に見過ごせなかったものとして、入門者に誤解を与えるというか、sedの魅力を半減させかねない記述があったので、それも触れておきます。「-e」オプションの説明として、ワンライナーとして使う場合「-e」オプションに続けてスクリプトを記述します、という内容があります。これは完全に正しいのですが、ぶっちゃけ「-e」は要りません。もちろん著者の方もそれはご存知だと思います。ただ、sedの魅力は、コマンド体系がシンプル (たった1文字!) なので、コマンドラインからワンライナーでさくっと書けちゃう、という点があります。それなのに、不要な「-e」を付けてね、なんてタイプ数が増えてワンライナー向けの記述としては面倒くさいだけです。sedのシンプルさが損なわれてしまいます。複数コマンドを別引数として与える場合に「-e」が必要となりますが、記事のサンプルコードもほとんどが「-e」の要らない内容です。もちろん、シェルスクリプト中などで、可読性や安全性のために「-e」を明示するというのは理解できます。

これは余計なお世話かもしれませんが、入門者向けなら、サンプルはできるだけ実際的な例を挙げるともっと良かったんじゃないかなと思いました。ほとんどが「aaabbb」とかなので、これだと使ってみようという気もあまり起きないのではないかなと思いました。

そろそろ疲れてきたのでまとめると、入門者向けの記事としては重要な基礎をすっ飛ばしすぎている、中上級者向けの説明としては、目新しいことが何もない。結果的に、誰向けなのかよくわからなくて、誰も得るところがない、という内容になっています。もちろん、紙幅の都合で、重要なところも止むなく落とした、というのも理解はできます。それでも、比較的どうでもいい「b」とか「:」とかの制御系や、「y」とか (trで十分では?)、「w」とかニッチな機能に紙面を割いているのが解せません。少なくとも私は、この記事から得るものはありませんでした。また、これからsedを操作できるようになりたいと思う入門者の基礎固めにも役立たないと、私は思います。

以上、身銭を切って記事を買った結果として不満ばかりになってしまいましたが、私はsedが好きなので、こういった特集が組まれることはすごく良いことだと思います。