KernighanさんとRob Pikeさんの著書、 'The Unix Programming Environment'の第3章の「USING THE SHELL」にechoコマンドの話が出てくる。
echoコマンドはおそらくコマンドの中で一番シンプルな部類に入る。 このコマンドの仕事は「引数を標準出力に出力する」ただそれだけである。
例:
$ echo Hello World Hello World
しかし、shellの機能と組み合わせたときに、このコマンドは新価を発揮する。
$ echo *
とした場合は、* はshellで展開されて、カレントディレクトリの全ファイルのファイル名がechoの引数に渡される。 結果として、カレントディレクトリの全ファイル名が連なった文字列になる(スペースで区切られる)。
また、よく使うケースが、環境変数(shell変数)の内容を確認したいとき。
$ echo $SHELL /bin/bash
$SHELLもshell側で展開して、echoコマンドに渡している。 echoコマンドは*とか$SHELLとかの存在は知らない。 やっている仕事は本当に引数で渡された文字列を標準出力に出力しているだけである。
echoは単体で見たときに、まったく意味ある仕事をしていないように思えるが、 他のプログラムを組み合わせると、なくてはならないコマンドになってしまう。 という実にUNIXらしいプログラムである。
ちなみに、UNIX V7のechoのソースは下記のとおりとてもシンプル。
#include <stdio.h> main(argc, argv) int argc; char *argv[]; { register int i, nflg; nflg = 0; if(argc > 1 && argv[1][0] == '-' && argv[1][1] == 'n') { nflg++; argc--; argv++; } for(i=1; i<argc; i++) { fputs(argv[i], stdout); if (i < argc-1) putchar(' '); } if(nflg == 0) putchar('\n'); exit(0); }
たったこれだけの仕様なのに実は議論になっていることがある。
それは改行に関して。
echoは渡された引数を出力する際に、実は最後に改行を入れている。
$ echo Hello Hello $
改行が入らない場合は、
$ echo Hello Hello$
となる。
本当に渡された引数の文字列をオウム返しに出力したいなら、改行は入れるべきではない。 が、デフォルトが改行しない仕様だと、改行したいときは、
$ echo 'Hello >' Hello $
と'で囲みつつ、中で改行するという面倒なことになる。 なので、通常の用途では改行が入った方が良いだろうという判断でこの仕様になっている。
一方で、UNIX V7からは -n というオプションが追加され、改行が入らない動作も仕様に入った。
この改行が入れたくないという要求に対して、どういう仕様にするかの議論がある。
UNIX V7の解法では -n というオプションを追加したが、これの欠点は'-n'を改行付きでechoしたいとき。 以下のよう打つ必要があること。
$ echo -n '-n >' -n $
これは美しくないが機能する。
一方で、System Vは別の解法を実装した。 以下のように文字列の最後に \c を入れてもらうことで改行なしとした。
$ echo 'Hello\c' Hello$
これはこれでまずい点がある。\xx の制御コードを解釈するプログラムはいろいろあるが、 echoの出力を他のプログラムに食わせたい場合に、'\c'をそのまま渡せなくなってしまう。とか。 じゃあ、'\c'をそのまま渡すための特別な表記を考えるか、とかになったりと、、、複雑になる。
echoひとつとっても、仕様をきちんと考えるとなると実は奥が深い。 ということを学んだ。
仕様案がいくつか出たときに、どれにするかをどう決めれば良いか?
KernighanさんとRob Pikeさんは本の中で明快な指針を示している。
Since a command should by default execute its most commonly used function, the real echo appends the final newline automatically. (p78)
言葉をそのまま訳したわけではないが、つまり、
そのプログラムの本来やるべき仕事が、一番に頻繁に実行されるケースを、一番簡潔に実現すべきだ
ということだ。
この指針に従うと、echoの通常は改行ありとすべきで、改行なしは特殊ケースとして実現する。 さらに特殊ケースのために、特別な仕様を導入するべきではない。 特殊ケースは多少ユーザに不便を与えても、本来の仕様がシンプルのままの方がよい。 つまり、'\c'というコードを解釈させるべきではない。ということになる。