SCSH(Scheme Shell)スクリプト入門

 先月Daryl Leeが「It's time to learn Scheme」という記事の中で、C++のコードを生成する例を挙げてScheme言語の紹介をしていた。本稿では、SCSH(Scheme Shell)で書いた実用的な例――複数のファイル内のテキスト検索/置換、ファイルのソート、CSVファイルからHTMLファイルへのデータ変換――を紹介する。

 SCSHは、Schemeプログラミング言語をベースとしたスクリプト言語だ。shやbashの長いスクリプトに置き換わることと、Scheme言語をシェルスクリプト作成により向いたものに拡張することを目的として、Olin Shivers氏によって作成された。

 SCSHはUnixシステム(Linux、BSD、Cygwin)にLisp的なインターフェースを持たせるもので、SCSHでは正規表現のDSL(ドメイン固有言語)とawkのDSLを利用することができる。UnixとLispがそれぞれ元にしている考え方に違いがあるため、スクリプトの作成にPerlやシェルを使用しているUnixユーザには一見するとSCSHが奇妙に感じられるかもしれない。

Unixの考え方とLispの考え方

 Unixでは、「専門化」と「文字列」というキーワードで表わされる考え方をする。Unixにおける「専門化」の意味は、複数の仕事を行う一つの巨大なプログラムを作成するのではなく、それぞれは一つの仕事をうまく行う小さなプログラムを複数作成するということだ。そうすることにより、組み合わせて大きなプログラムを作成することのできる小さくて単純なコンポーネントが作成されるので、モジュール性が高まる。

 またUnixでは「文字列」を引数としてプログラムを実行することが、一つのプログラムから別のプログラムにデータを渡すための唯一の方法となっている。言い換えれば、渡されるデータのデータ型が失われるため、データを受け取るプログラムがデータをパースして文字列を適切なデータ型に変換する必要があるということだ。例を挙げると、「kill 223」を実行したときには、「223」という文字列がパースされて数値に変換される。このように、入力を受け取るUnixのプログラムはすべて、受け取った文字列を何らかの必要なデータ型のオブジェクトに変換するパースを自ら行わなければならない。そのためオブジェクトとして受け渡しを行うことが面倒になっている。

 (Scheme系の言語でもCommon Lisp系の言語でも)Lispのプログラムでは、モジュール性が同様に好まれるものの、整数/シンボル/リストなどのオブジェクトという形でプログラム間でデータを受け渡しするということも好まれる。このことは例えばEmacsにも見ることができて、Emacsでは文字列だけではなく様々な型のオブジェクトを扱う複数の小さなEmacs-Lispプログラムが使用されている。

SCSH(Scheme Shell)の特徴

 SCSHでは、他のたいていの言語とは異なり正規表現エンジンが文字列ベースでは“なく”、Lisp風の文法を持った組み込みDSLになっている。またSCSHでは「/」(スラッシュ)をシンボル名の中で使用することができるので、文字列型を使用せずにファイル名を作成することができる。さらにSCSHではサーバやクライアントの作成を自動化する高レベル関数も備えたネットワークソケットインターフェースが提供されている。

 正規表現を作成するための文法は「SRE」と呼ばれるもので、Schemeに似ている(つまりリストの集まり)。文字列である通常の正規表現の表記法と比べると、正規表現を説明するためのコメントを書き加えることができたり、正規表現を組み合わせて作成することができたりするなどの利点がいくつかある。SREコードにコメントを書き加えることは、Schemeのコメントを書き加えることで行われる。SREはリストなので、Perlのようにコメントを正規表現の表記中に直接的に書き入れる必要はない(そのような書き方は正規表現のPOSIX標準に反していて、おそらく他の正規表現エンジンとの互換性はない)。このことは例えばPerlの正規表現で書いた数独の解答プログラムや、有名な電子メール確認用の正規表現など、長々しい正規表現が必要な場合に役立つ。正規表現には実行時に具体的な内容の決まる動的正規表現を使用することもできる。これはPerlなどの言語で行うことのできる変数展開に似ているが、SCSHでは変数展開がPOSIXの正規表現の標準とかち合うことがないという点が異なる。

 Lispのマクロを使えば、コンパイル時に文法を操作することができる。つまり自分で自由に新しい文法を定義することができるということだ。Schemeの仕様ではマクロは構文と呼ばれていて、Schemeには新たな構文を定義するのに役立つパターンマッチングツールがある。SCSHでは、正規表現エンジン、プロセスの表記法、awkの表記法はすべてマクロ(構文)として定義されている。新たな構文を定義することは、行いたいことの乱雑な詳細を隠蔽するのに役立つ。例えばawkの構文では、使用するべきレコードリーダーをユーザが指定できるようにすることで、レコードを検索するためにファイルを一行ずつループで処理するコードを隠蔽している。