[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

10. ソフトウェア・ツールボックスを開く(Opening the software toolbox)

この章はもともとLinux Journal,volume 1,number 2のWhat's GNU?で記載されました.それは,Arnold Robbinsによって書かれました.


ツールボックスの紹介

今月のコラムは,GNUプロジェクトの周辺に関連するもので,そこでは,Linuxシ ステム上のGNUツールのいくつかと,それらの使われ方を記述します.それは正 に,プログラム開発と使用方法の"ソフトウェアツール"の哲学です.

ソフトウェアツールの哲学は,初期設計と(LinuxとGNUが本質的に複製している) Unixの開発では,重要で不可欠な概念でした.不幸にも,インターネットワーキ ングと派手なGUIの現在の出版では,それは王道からそれてしまっているように 感じられます.それは強力な多くの種類の問題を解決するための精神的なモデル を提供するので残念です.

多くの人は,ズボンのポケット(またはハンドバッグ)に,スイスのアーミーナイ フを持ち運んでいます.スイスのアーミーナイフは有用なハンディーツールです. それはいくつかのナイフの刃,ネジ回し,毛抜き,楊子,爪やすり,栓抜き,そ しておそらくその他のいくつかがあります.毎日の,単純な汎用のツールが必要 な小さな様々な仕事でおあつらえ向きです.

一方,経験豊富な大工は,スイスのアーミーナイフを使用して家を建てません. その代わりに,専門的な道具--のこぎり,かなづち,ネジ回し,かんな等がぎっ しり詰まった道具箱を持っています.そして,それぞれの道具を使用する時と場 所を知っています.ネジ回しを扱いながら,釘を打っているところを見たことは ないでしょう.

ベル研究所のUnix開発者は,全て専門的なプログラマと訓練されたコンピュータ 科学者です.彼らは,1つのプログラムのみを利用するため,1つで全てに適する プログラムをユーザに提示する一方,そのようなプログラムは以下のようになる ことが分かりました.

  1. 書くのが難しい.

  2. 管理とデバックが難しい.

  3. 新しい状況に対し拡張が難しい.

その代わりに,プログラムは専門的なツールであるべきだと感じました.要する に,それぞれのプログラムは,"1つのことを上手にすべきである"ということ です.それ以上でも以下でもありません.そのようなプログラムは,設計,作成 がより単純で,正しいものを得られます--ただ1つのことをするだけです.

更に彼らは,良いマシンでプログラムを一緒にハックするため,全体は部分の集 合より偉大なことに気付きました.いくつかの特別な目的のプログラムを組み合 わせることで,プログラムが設計された目的には無い特定の仕事を達成したり, 特定目的のプログラムを書く必要がある場合,より速く簡単にそれを達成したり できました.我々は,このコラムでこれ以上の,いくつかの(古い)例を見ます. (重要な追加点は,まだいくつかのアプリケーションがツールボックスに無い場 合,必要があれば回り道して,最初に必要なソフトウェアツールを構築すること です.)


I/O リダイレクション

希望としては,皆さんが,"標準入力","標準出力",そして"標準エラー出 力" の特定の概念で,シェルのI/Oリダイレクションの基本に慣れています.要 するに,"標準入力"はデータソースで,データがやってくるところです.デー タソースが,ディスクファイル,キーボード,磁気テープやパンチカードかどう か,プログラムは知る必要も注意する必要もありません.同様に,"標準出力" はデータシンクで,データが出て行くところです.プログラムはその場所を知る 必要も注意する必要もありません.標準入力を読み込み,データに何かを行い, それを送り続けるプログラムは,"フィルタ"と呼ばれ,それは水のパイプライ ンでのフィルタに似ているためです.

Unixシェルを用いた場合,データパイプラインを設定することは非常に簡単です.

 
program_to_create_data | filter1 | .... | filterN > final.pretty.data

我々は生データを作ることから始めます.それぞれのフィルタは,それがパイプ ラインから出てくるまで,いくつかの連続した変換をデータに適用し,それは望 ましい形式です.

これは素晴らしく,標準入力と標準出力に適しています.標準エラー出力は,動 作中どこに行きますか? まあ,上記のパイプラインfilter1について考 えて見てください.データでエラーが発生した場合,何が生じるのでしょう? エラーメッセージを標準出力に書き出す場合,それはfilter2の入力のパ イプラインの下に隠れ,ユーザーはおそらく見ることはありません.そのため, プログラムはユーザに注意を促すため,エラーメッセージを送ることが可能な場 所が必要です.これは標準エラー出力で,画面から離れているプログラムの標準 出力をリダイレクトしてさえ,それは通常コンソールやウィンドウに連結してい ます.

フィルタプログラムが一緒に動作するため,データの書式は合意されている必要 があります.最も簡単で最も容易な書式は,単なるテキストの行です.通常, Unixデータファイルは,慣習でUnixの文献で"改行"と呼ばれる,ASCII LF (Line Feed)文字で分けられた行を用いた,単なるバイトのストリーム です.(これは,Cプログラマの場合は'\n'です.)これは全ての伝統的な フィルタプログラムで用いられる書式です.(多くのより早期のオペレーティン グシステムは,バイナリデータを管理するため,手の込んだファシリティと特別 な目的を持つプログラムがありました.Unixは常にそのようなことから身をかわ していて,哲学の下では,テキストエディタでデータを見たり編集したりするこ とを単純に可能にする,最も簡単な方法です.)

OK,十分紹介しました.いくつかの道具をひと目見て,それから,興味深い方法 でそれらを一緒に束ねる方法を見ましょう.以下の議論では,これらの興味ある コマンドラインオプションを紹介するだけです.常に行うように,完全な話とす るために,システムドキュメントを再点検してください.


whoコマンド

最初のプログラムはwhoコマンドです.単独では,それは現在ログインし ているユーザのリストを生成します.私はシングルユーザシステムでこれを書い ていますが,我々は複数の人々がログインしているふりをします.

 
$ who
arnold   console Jan 22 19:57
miriam   ttyp0   Jan 23 14:19(:0.0)
bill     ttyp1   Jan 21 09:32(:0.0)
arnold   ttyp2   Jan 23 20:48(:0.0)

ここで,`$'は通常のシェルプロンプトで,そこで私はwhoと入力し ました.3人ログインしていて,私は2回ログインしてます.伝統的なUnixシステ ムでは,ユーザ名は8文字以上の長さはありません.このわずかな平凡なビット は後で有用になります.whoの出力は良いのですが,データは余り面白く ありません.


cutコマンド

次に我々が見るプログラムはcutコマンドです.このプログラムは,入力 データの列やフィールドを切り取ります.例えば,我々はそれを用いて, `/etc/passwd'ファイルからログイン名とフルネームのみを出力させること ができます.`/etc/passwd'ファイルは,7つのフィールドがあり,コロン で分かれています.

 
arnold:xyzzy:2076:10:Arnold D. Robbins:/home/arnold:/bin/ksh

1番目と5番目のフィールドを得るため,以下のようにcutを使用します.

 
$ cut -d: -f1,5 /etc/passwd
root:Operator
…
arnold:Arnold D. Robbins
miriam:Miriam A. Robbins
…

`-c'オプションを用いた場合,cutは,入力行の指定した文字(例え ば,列)を切り出します.このコマンドは,データのフィルタリングに役立ちそ うです.


sortコマンド

次に見るのはsortコマンドです.これはUnix形式のシステムで最も強力 なコマンドの1つです.自分で良く利用していると思うのは,おしゃれなデータ の配管を設定している時です.sortコマンドは,コマンドラインで指名 されたそれぞれのファイルを読み込みソートします.それはソートされたデータ を統合し,標準出力に書き出します.それはファイルがコマンドラインで与えら れない場合,標準入力から読み込みます(このため,フィルタになります).ソー トは,順序を正しくするとき文字を基本としたり,ユーザが供給する基準の順番 を基本としたりします.


uniqコマンド

(少なくとも今のところ)最後に,我々はuniqプログラムを見ます.デー タをソートするとき,重複行,すなわち同一行でよく終ります.通常,それぞれ の行に1つのインスタンスが必要です.これはuniqを用いる場所です. uniqはその標準入力から読み込み,それはソートされてることを期待し ます.それは重複行の1つのコピーのみを出力します.それにはいくつかのオプ ションがあります.後に,我々は`-c'オプションを使用し,それはそれぞ れユニークな行を出力し,入力で行が発生した回数の数えたものを前置します.


ツールの統合

さて,これが多数のユーザがログインしている大きなBBSシステムだと考えましょ う.管理者はシスオペに,ログインしているユーザのソートされたリストを生成 するプログラムを書かせたいとします.更に,ユーザが複数回ログインしていて も,彼または彼女の名前を出力に1度しか表示させないものとします.

シスオペはシステムドキュメントを持って席に付き,これを行うCプログラムを 書いたはずです.それはおそらく,200行のコードを書いて,テストして,デバッ グするため,2時間かけているでしょう.しかし,ソフトウェアツールボックス を知っている場合,シスオペは代わりに,ログインしているユーザのリストを生 成することから始めることができます.

 
$ 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

ここで注意すべき主な点が4つあります.最初に,4つのプログラムのみのコマン ドラインで,シスオペは仕事に費す2時間を節約することができました.さらに, シェルパイプラインはCプログラムが行うのと同じ効果があり,それはプログラ マの時間に関してはるかに効果的です.人々の時間はコンピュータの時間よりも はるかに高価で,現在の"全てのことをする十分な時間が無い"社会では,プロ グラマの時間の2時間を節約することは,並々ならぬ目ざましい成果です.

2番目に,ツールの組み合わせで,個別のプログラマの著者が想像してい なかった特定の目的の仕事をすることが可能だということを強調することも重要 です.

3番目に,我々がここで行ったように,ステージ内ででパイプラインを組み上げ ることも価値があります.これで,パイプラインのそれぞれのステージでのデー タを見ることが可能になり,それは,これらのツールを全く正しく使用している ことの確信を得る助けになります.

最後に,シェルスクリプトでパイプラインを組み上げることで,他のユーザがそ のコマンドを使用することができ,それらを設定したおしゃれな配管を覚える必 要がありません.それを実行する方法という意味では,シェルスクリプトとコン パイルされたプログラムは区別できません.

ここまでの準備運動の後で,我々は2つの追加のより複雑なパイプラインを見ま す.そのため,我々が2つのツールをさらに紹介する必要があります.

最初はtrコマンドで,それは"transliterate(変換)"を意味します. trコマンドは,文字対文字を基本に,文字を変換する作用があります. 通常,それは大文字を小文字に割り当てることに使用されます.

 
$ echo ThIs ExAmPlE HaS MIXED case! | tr '[A-Z]' '[a-z]'
this example has mixed case!

重要ないくつかのオプションがあります.

` -c'

リストアップされた文字の補集合で動作し,すなわち,与えられた集合に無い文 字に適応した処理です.

` -d'

出力から最初のセットの文字を削除します.

` -s'

出力で繰り返される文字を1文字に圧縮します.

我々は,一度に3つの全てのオプションを使用します.

我々が見る,もう1つのコマンドはcommです.commコマンドは,2 つのソートされた入力ファイルを入力データとし,ファイルの行を3列に出力し ます.出力列は最初のファイルのユニークなデータ行.2番目のファイルのユニー クなデータ行,そして,両方に共通なデータ行です.`-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に伝えます.

さて,我々はおしゃれなパイプラインを構築する準備ができました.最初の応用 は,単語の頻度カウンタです.これは,著者が特定の単語を過度に使用している かどうかを決定する助けとなります.

最初のステップは,入力ファイルの全ての文字の大文字小文字をどちらか1つに 変換することです."The"と"the"は数えているときは同じ単語です.

 
$ tr '[A-Z]' '[a-z]' < whats.gnu | ...

次のステップは,句読点をを取り除くことです.引用された単語と引用されてい ない単語は,同一に扱われるべきです.句読点を片付ける最も簡単な方法です.

 
$ tr '[A-Z]' '[a-z]' < whats.gnu | tr -cd '[A-Za-z0-9_ \012]' | ...

2番目のtrコマンドは,リストアップされた文字の補集合を処理し,それ は全ての文字,数字,アンダースコアと空白です.`\012'は改行を表現し ます.それはそのまま残す必要があります.(ASCIIタブ文字も,生成され たスクリプトでは追加として含まれるべきです.)

この時点で,我々は,空白スペースで分けられた単語からなるデータを持ってい ます.単語は英数文字(とアンダースコア)のみ含みます.次のステップは,1行 に1単語となるように,データを別々に分けます.これは数える処理をより容易 にするためで,まもなく見ることができます.

 
$ tr '[A-Z]' '[a-z]' < whats.gnu | tr -cd '[A-Za-z0-9_ \012]' |
> tr -s '[ ]' '\012' | ...

このコマンドは空白を改行に切替えます.`-s'オプションは,出力の複数 の改行文字を1つに圧縮します.これは空白行を避けたいとき助かります. (`>'はシェルの"2番目のプロンプト"を意味します.これは,全てのコマ ンドを入力し終えていないことに注意させるとき,シェルが出力するものです.)

我々は今,1行に1単語で,句読点が無く,全て大文字小文字どちらかだけのデー タを持っています.我々はそれぞれの単語を数える準備ができました.

 
$ 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

出力は単語でソートされていて,総数ではありません! 我々が欲しいのは,最 も頻繁に使用される最初のものです.幸い,これは簡単に達成でき,2つの 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
 ...

やれやれ! それは大量の要約です.まだ同じ原則は適用されます.6つのコマン ド2行で(本当は利便性のため長いものを分けたものです),我々は興味深く便利 なことを行うプログラムを作成し,それは,Cプログラムで同じことをするもの を書くよりはるかに短い時間でした.

上記のパイプラインへのちょっとした変更で,単純なスペルチェッカーを与える ことができます.単語を正しく綴っているかどうかを決定するために行う必要が あることは,辞書で調べることです.それが無い場合,可能性としては綴りが正 しくないということです.そのため,我々は辞書が必要です.Slackware Linux 配布物を持っている場合,ファイル`/usr/lib/ispell/ispell.words'があ り,それはソートされていて,38,400語の辞書です.

さて,我々のファイルと辞書をいかにして比較するのでしょう? 以前に我々は, ソートされた,1行に1単語の単語リストを生成しました.

 
$ 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/lib/ispell/ispell.words

`-2'と`-3'オプションは,辞書(2番目のファイル)のみにある行と, 両方のファイルにある行を削除します.最初のファイル(我々の単語ストリーム の標準入力)のみにある行は,辞書にはありません.これらは綴りエラーに対す る好ましい候補です.このパイプラインは,Unixでのスペルチェッカー製品とし て,最初に発生しました.

ちょっと記述する価値のある,その他のツールもあります.

grep

正規表現に一致するテキストをファイルで検索します.

egrep

grepに似ていますが,より強力な正規表現を用います.

wc

行,単語,文字を数えます.

tee

データパイプに対するT部品で,データをファイルと標準出力にコピーします.

sed

ストリームエディタで,より進んだツールです.

awk

データ操作言語で,もう1つのより進んだツールです.

ソフトウェアツールの哲学は,以下の短い助言も含んでいます."難しい部分は 他人にさせろ".これは,必要なほとんどのものは与えられるものであり,必要 な形式にするまでの方法が残っていることを意味します.

要約します.

  1. それぞれのプログラムは,1つのことでうまく働きます.それ以上でもそれ以下 でもありません.

  2. 適切な配管でプログラムを組み合わせることで,全体として部分の総和以上の結 果を導きます.それは,著者が想像していなかったプログラムの新しい使用法も 導きます.

  3. プログラムは,決して余分なヘッダや末尾のデータを出力すべきではなく,それ はこれらがパイプラインを壊してしまうものを送るはずだからです.(この点は 以前に記述していません.)

  4. 難しいことは,他人にさせましょう.

  5. ツールボックスを理解してください! それぞれのプログラムを適切に使用して ください.適切なツールが無い場合,それを構築してください.

ここで書いている我々が議論してきた全てのプログラムは, `/pub/gnu/textutils-1.9.tar.gz'として,prep.ai.mit.eduからの 匿名ftpで利用可能です.(2)

私がこのコラムで表現したものに新しいものはありません.ソフトウェアツール の哲学は,最初に,Brian KernighanとP.J. PlaugerによるSoftware Toolsの本(Addison-Wesley, ISBN 0-201-03669-X)で紹介されました.この本は, ソフトウェアツールの書き方と使用法を表しています.それは1976年に書かれ, ratfor (RATional FORtran)という名のFORTRANに対するプリプロセッサ を使用しています.当時,Cは現在ほどubiquitousではなく,FORTRANはそうでし た.最後の章で,ratforをFORTRANにするプロセッサを提示していて, ratforで書かれています.ratforはCに非常に似ています.Cを知っ ている場合,コードを追いかけるのに問題ないでしょう.

1981年に本は更新され,Software Tools in Pascal (Addison-Wesley, ISBN 0-201-10342-7)として利用可能になりました.両方の本は印刷されていて, プログラマにとっては読む価値があります.それらは,確かにプログラミングを 見る方法で,主な変化をなし得ました.

初めに,両方の本のプログラムはAddison-Wesleyから(9トラックテープで)利用 可能でした.不幸にも,これはもはや利用できず,Internetの周辺でコピーがあ るかも知れません.何年もの間,活発なSoftware Tools Users Groupがあり,そ のメンバーは元のratforプログラムを,FORTRANコンピュータを持つ全て のコンピュータに本質的に移植しました.グループの人気は,Unixが大学を越え て広がり始めたので,80年代半ばで衰えました.

GNUコードとその他のUnixプログラムのクローンの現在の増殖で,これらのプロ グラムは,現在ほとんど注目されません.現在のCのバージョンはより効果的で, これらのプログラムが行うより多くのことを行います.にもかかわらず,良いプ ログラミングスタイルの博覧会と,still-valuableの哲学に対する福音として, これらの本は比べるものが無く,私は高く推薦します.

謝辞:私はこのコラムのレビューに対し,ベル研究所のBrian Kernighanと,オ リジナルのソフトウェアToolsmithに深く感謝したいと思います.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Akihiro Sagawa on June, 15 2005 using texi2html 1.70.