さて,これが多数のユーザがログインしている大きなBBSシステムだと考えま しょう.管理者はシスオペに,ログインしているユーザのソートされたリスト を生成するプログラムを書かせたいとします.更に,ユーザが複数回ログイン していても,彼または彼女の名前を出力に一度しか表示させないものとします.
管理者はシステムドキュメントを持って席に付き,これを行うCプログラムを 書いたはずです.それはおそらく,200行のコードを書いて,テストして,デ バッグするため,二時間かけているでしょう.しかし,ソフトウェアツールボッ クスを知っている場合,シスオペは代わりに,ログインしているユーザのリス トを生成することから始めることができます.
$ who | cut -c1-8 -| arnold -| miriam -| bill -| arnold
次に,リストをソートします.
$ who | cut -c1-8 | sort -| arnold -| arnold -| bill -| miriam
終りに,重複を取り除くため,ソートされたリストをuniqに通しま す.
$ who | cut -c1-8 | sort | uniq -| arnold -| bill -| miriam
sortコマンドには,実際は,uniqを行う-uオ プションがあります.しかし,uniqは,‘sort -u’で代用でき ない他のユーザのためです.
管理者は,このパイプラインをシェルスクリプトに書き出し,システムの全て のユーザが利用可能にしました.
# cat > /usr/local/bin/listusers who | cut -c1-8 | sort | uniq ^D # chmod +x /usr/local/bin/listusers
ここで注意すべき主な点が四つあります.最初に,四つのプログラムのみのコ マンドラインで,管理者は仕事に費す二時間を節約することができました.さ らに,シェルパイプラインはCプログラムが行うのと同じ効果があり,それは プログラマの時間に関してはるかに効果的です.人々の時間はコンピュータの 時間よりもはるかに高価で,現在の“全てのことをする十分な時間が無い” 社会では,プログラマの時間の二時間を節約することは,並々ならぬ目ざまし い成果です.
二番目に,ツールの組み合わせで,個別のプログラマの著者が想像し ていなかった特定の目的の仕事をすることが可能だということを強調すること も重要です.
三番目に,我々がここで行ったように,ステージ内ででパイプラインを組み上 げることも価値があります.これで,パイプラインのそれぞれのステージでの データを見ることが可能になり,それは,これらのツールを全く正しく使用し ていることの確信を得る助けになります.
最後に,シェルスクリプトでパイプラインを組み上げることで,他のユーザが そのコマンドを使用することができ,それらを設定したおしゃれな配管を覚え る必要がありません.それを実行する方法という意味では,シェルスクリプト とコンパイルされたプログラムは区別できません.
ここまでの準備運動の後で,我々は二つの追加のより複雑なパイプラインを見 ていきます.そのため,我々が二つのツールをさらに紹介する必要があります.
最初はtrコマンドで,それは“transliterate(変換)”を意味しま す.trコマンドは,文字対文字を基本に,文字を変換する作用があ ります.通常,それは大文字を小文字に割り当てることに使用されます.
$ echo ThIs ExAmPlE HaS MIXED case! | tr '[A-Z]' '[a-z]' -| this example has mixed case!
重要ないくつかのオプションがあります.
-c
-d
-s
我々は,一度に三つの全てのオプションを使用します.
我々が見ていく,もう一つのコマンドはcommです.comm コマンドは,二つのソートされた入力ファイルを入力データとし,ファイルの 行を三列に出力します.出力列は最初のファイルのユニークなデータ行.二番 目のファイルのユニークなデータ行,そして,両方に共通なデータ行です. -1,-2と-3のコマンドラインオプションは,対 応する列を削除します.(これは直観的ではなく,慣れるのに少しかか ります.) 例えば,以下のようにします.
$ cat f1 -| 11111 -| 22222 -| 33333 -| 44444 $ cat f2 -| 00000 -| 22222 -| 33333 -| 55555 $ comm f1 f2 -| 00000 -| 11111 -| 22222 -| 33333 -| 44444 -| 55555
ファイル名としての単一のダッシュは,通常のファイルの代わりに標準入力か ら読みとるよう,commに伝えます.
さて,我々はおしゃれなパイプラインを構築する準備ができました.最初の応 用は,単語の頻度カウンタです.これは,著者が特定の単語を過度に使用して いるかどうかを決定する助けとなります.
最初のステップは,入力ファイルの全ての文字の大文字小文字をどちらか一つ に変換することです.“The”と“the”は数えているときは同じ単語です.
$ tr '[A-Z]' '[a-z]' < whats.gnu | ...
次のステップは,句読点をを取り除くことです.引用された単語と引用されて いない単語は,同一に扱われるべきです.句読点を片付ける最も簡単な方法で す.
$ tr '[A-Z]' '[a-z]' < whats.gnu | tr -cd '[A-Za-z0-9_ \012]' | ...
二番目のtrコマンドは,リストアップされた文字の補集合を処理し, それは全ての文字,数字,アンダースコアと空白です.‘\012’は改行を 表現します.それはそのまま残す必要があります.(ASCIIタブ文字 も,生成されたスクリプトでは追加として含まれるべきです.)
この時点で,我々は,空白スペースで分けられた単語からなるデータを保持し ていることになります.単語は英数文字(とアンダースコア)のみ含まれている ものです.次のステップは,一行に一単語となるように,データを別々に分け ます.これは数える処理をより容易にするためで,さらに,短くなります.
$ tr '[A-Z]' '[a-z]' < whats.gnu | tr -cd '[A-Za-z0-9_ \012]' | > tr -s '[ ]' '\012' | ...
このコマンドは空白を改行に切替えます.-sオプションは,出力の 複数の改行文字を一つに圧縮します.これは空白行を避けたいとき助かります. (‘>’はシェルの“二番目のプロンプト”を意味します.これは,全ての コマンドを入力し終えていないことに注意させるとき,シェルが出力するもの です.)
我々は今,一行に一単語で,句読点が無く,全て大文字小文字どちらかだけの データを持っています.我々はそれぞれの単語を数える準備ができました.
$ tr '[A-Z]' '[a-z]' < whats.gnu | tr -cd '[A-Za-z0-9_ \012]' | > tr -s '[ ]' '\012' | sort | uniq -c | ...
この時点で,データは以下のようになります.
60 a 2 able 6 about 1 above 2 accomplish 1 acquire 1 actually 2 additional
出力は単語でソートされていて,総数ではありません! 我々が欲しいのは, 最も頻繁に使用される最初のものです.幸い,これは簡単に達成でき,二つの sortオプションの助けを借ります.
-n
-r
最終的なパイプラインは以下のようになります.
$ tr '[A-Z]' '[a-z]' < whats.gnu | tr -cd '[A-Za-z0-9_ \012]' | > tr -s '[ ]' '\012' | sort | uniq -c | sort -nr -| 156 the -| 60 a -| 58 to -| 51 of -| 51 and ...
やれやれ! それは大した要約です.まだ同じ原則は適用されます.六つのコ マンド二行で(本当は利便性のため長いものを分けたものです),我々は興味深 く便利なことを行うプログラムを作成し,それは,Cプログラムで同じことを するものを書くよりはるかに短い時間でした.
上記のパイプラインへのちょっとした変更で,単純なスペルチェッカーを与え ることができます.単語を正しく綴っているかどうかを決定するために行う必 要があることは,辞書で調べることです.それが無い場合,可能性としては綴 りが正しくないということです.そのため,我々は辞書が必要です. Slackware Linuxの配布物では,ファイル /usr/lib/ispell/ispell.wordsがあり,それはソートされていて, 38,400語の辞書です.
さて,我々のファイルと辞書をいかにして比較するのでしょう? 以前に我々 は,ソートされた,一行に一単語の単語リストを生成しました.
$ tr '[A-Z]' '[a-z]' < whats.gnu | tr -cd '[A-Za-z0-9_ \012]' | > tr -s '[ ]' '\012' | sort -u | ...
さて,必要なことは辞書に無い単語リストです.ここが, commコマンドを用いる場所です.
$ tr '[A-Z]' '[a-z]' < whats.gnu | tr -cd '[A-Za-z0-9_ \012]' | > tr -s '[ ]' '\012' | sort -u | > comm -23 - /usr/dict/words
-2と-3オプションは,辞書(二番目のファイル)のみにある 行と,両方のファイルにある行を削除します.最初のファイル(我々の単語ス トリームの標準入力)のみにある行は,辞書にはありません.これらは綴りエ ラーに対する好ましい候補です.このパイプラインは,Unixでのスペルチェッ カー製品として,最初に発生しました.
ちょっと記述する価値のある,その他のツールもあります.
ソフトウェアツールの哲学は,以下の短い助言も含んでいます.“難しい部分 は他人にさせろ”.これは,必要なほとんどのものは与えられるものであり, 必要な形式にするまでの方法が残っていることを意味します.
要約します.
ここで書いている我々が議論してきた全てのプログラムは, ftp://gnudist.gnu.org/textutils/textutils-1.22.tar.gzから匿名 ftpで利用可能です.(現在はより新しいバージョンが利用可能かも しれません.)
私がこのコラムで紹介したものに新しいものはありません.ソフトウェアツー
ルの哲学は,最初に,Brian KernighanとP.J. PlaugerによるSoftware
Toolsの本(Addison-Wesley, ISBN 0-201-03669-X)で紹介されました.この本
は,ソフトウェアツールの書き方と使用法を表しています.それは1976年に書
かれ,ratfor
(RATional FORtran)という名のFORTRANに対するプリプ
ロセッサを使用しています.当時,Cは現在ほど,どこにでもあるといったも
のではなく,FORTRANはそういうものでした.最後の章で,ratfor
を
FORTRANにするプロセッサを提示していて,ratfor
で書かれています.
ratfor
はCに非常に似ています.Cを知っている場合,コードを追いか
けるのに問題ないでしょう.
1981年に本は更新され,Software Tools in Pascal (Addison-Wesley, ISBN 0-201-10342-7)として利用可能になりました.両方の本は印刷されてい て,プログラマが読む価値はあります.それらは,確かにプログラミングの見 方を大きく変化させました.
初めに,両方の本のプログラムはAddison-Wesleyから(9トラックテープで)利
用可能でした.不幸にも,これはもはや利用できませんが,ratfor
バージョンはBrian Kernighan's home pageで利用可能で,Internetのどこかにコピーがあるかもしれません.
何年もの間,活発なSoftware Tools Users Groupがあり,そのメンバーは元の
ratfor
プログラムを,FORTRANコンピュータを持つ全てのコンピュータ
に本質的に移植しました.グループの人気は,Unixが大学を越えて広がり始め
たので,80年代半ばで衰えました.
GNUコードとその他のUnixプログラムのクローンの現在の増殖で,これらのプ ログラムは,現在ほとんど注目されません.現在のCのバージョンはより効果 的で,これらのプログラムが行うより多くのことを行います.にもかかわらず, 良いプログラミングスタイルの博覧会と,still-valuableの哲学に対する福音 として,これらの本は比べるものが無く,私は高く推薦します.
謝辞:私はこのコラムのレビューに対し,ベル研究所のBrian Kernighanと, オリジナルのソフトウェアToolsmithに深く感謝したいと思います.