• The Wild Wild Card

ファイルを探すときや複数ファイルを同時指定するときなどに「ワイルドカード」が使えるオペレーティングシステムは多い。MS-DOSでも最初から“*”と“?”のワイルドカード文字が使えた。これは、手本としたCP/Mでも実装されていたからだ。

1974年に作られたCP/Mは、旧DEC社のオペレーティングシステムTOPS-10を参考にしていたとされる。TOPS-10には、“*”と“?”のワイルドカード文字があった。このため、CP/Mにも同じワイルドカードがあった。MS-DOSは、8 bit CPU版のCP/Mを手本に作られたため同じワイルドカードを持っていた。

現在のbashにも同様の機能として「パス名展開」が装備されている。これは、初期のUnixに搭載されていたglob(globalの略とされる)というプログラムに由来する。現在のbashでも、パス名展開関連の環境変数にこの名前が残る。初期のglobも“*”と“!”のワイルドカード文字を使う。ただし、bashなどのパス名展開は、globを元にしているが、同じものではない。

Unix V1に搭載されていたglobは、シェル(sh)などから呼び出されるプログラムだったとされている。shの引数として引用符のないものがあったとき、このglobを使って、実在のパスに変換が行われた。

UNIXのglobがTOPS-10のワイルドカードを参考にしたのかどうかは確認することができなかった。しかし最初のUNIXがpdp-11に搭載されたことを考えると、両者は近い関係があったとは推察できる。

一言で「ワイルドカード」というが、実装は、それぞれ異なる(表01)。Windowsでは、現在でもワイルドカードを展開するかどうかアプリケーション側の責任だが、開発言語のランタイムなどで対応できることが多い。コマンドライン・インタプリタ(シェル)のcmd.exeもアプリケーションに対して、特にワイルドカードのサポートは行わない。しかし、組み込みコマンドでは、ワイルドカード文字を受け付け、これを処理できる。対応しているのは、“*”と“!”のみである。

  • ■表01

cmd.exeでは、“*”によるファイル名の一致は8.3形式の短いファイル名に対しても行われる(写真01)。MS-DOSを使ったことがないユーザーは、8.3形式のことなど知らないと思われるので、cmd.exeのdelコマンドなどでワイルドカード文字を使わないほうが無難である。

  • 写真01: cmd.exeでは、8.3形式のファイル名に対してもワイルドカードによる照合が行われる。8.3形式では末尾に数字が使われ末尾に数字を指定した*を含むパターンが一致することがある。そのため、delコマンドで“*”使うと思わぬファイルを削除してしまうことがある。8.3形式のファイル名を見るには、“dir /x”コマンドを使う

同じWindowsのPowerShell(およびWindows PowerShell)は、コマンドの一部は、引数に指定されたパスでワイルドカードを処理する。ただし、既存のexeコマンドに対してbashのようにパス名展開などを行って起動することはない。また、PowerShellは8.3形式のファイル名を扱わない。このため、cmd.exeのような問題は発生しない。

このPowerShellでは、“*”と“!”に加えて“[ ]”による文字範囲指定が行える。この点では、bashに近いのだが、ワイルドカード文字の意味を打ち消すエスケープ文字として逆クオート“`”を使う点が異なる。また、bashなどがもつ文字クラスや文字範囲の否定などの機能もない。bashと大きく違うのは、PowerShellは、コマンド引数でパスを受け取る位置が決まっているため、ダブルクオート、シングルクオートで囲まれていてもワイルドカードが有効になる点だ。

bashのワイルドカードは「パス名展開」(pathname expansion)と呼ばれる(manページ参照)。パス名展開は、コマンドラインの引数のうちシングル、ダブルクオートで囲まれていない部分が対象で、かつ、実在のパスに限って展開が行われる。逆にいうと、引用符で括らない引数にワイルドカード文字が含まれると、すべてパス名展開される可能性がある(マッチするパスが存在するかどうかに依存)。

bashのパス名展開では、“[[.space.]]”(スペース文字)、“[[.ampersand.]]”(&文字)という表記が利用できる。通常、スペースを含むパス名は、シングル、ダブルクオートで括らないと、引数の区切りとみなされるが、括るとパス名展開の対象とならない。このような場合にスペース文字の代わりに“[[.space.]]”を使うことができる(写真02)。bashのmanページでは、これを“collating symbol”だとしている。インターネット検索すると、これはロケールで定義されているcollating-symbolだとする文書が幾つか見つかる。しかし、ロケールのcollating-symbolと“[[.space.]]”という表記はちょっと違うようだ。ロケールの定義ファイルにspaceなどのcollating-symbol定義が見つからない。

  • 写真02: bashのパス名展開は、シングル、ダブルクオートで括られていないときに適用される。また角括弧([ ])の中では、文字クラスなどが利用できる。そのほか“[[.space.]]”のようにスペース文字などに対応した表記が利用できる

調べてみると、bashのソースコードcollsyms.hにcollating symbolの定義がある。ここを見る限り、ASCIIコード文字に名前をつけて“[. .]”て囲って参照しているようである。なお、ASCIIコード文字の名前で2語になっていて間にスペースの入るものは、ハイフンに置き換えられているようだ。たとえば、“#”なら“number-sign”になる。

正規表現に比べたら、ワイルドカードなんて簡単と思えるが、意外に面倒な部分がある。それぞれのシェルで実装が異なり、ワイルドカードなんてみんな同じと考えると痛い目に合いそうだ。

今回のタイトルネタは、1965年の米国テレビドラマ“The Wild Wild West”(邦題 0088/ワイルド・ウエスト)である。1962年に始まる007シリーズはスパイ物を流行させ、テレビでも多数のスパイドラマが作られた。当初は“The Man from U.N.C.L.E.”(邦題0011ナポレオン・ソロ)のような正統派も多かったが、激しい競争ゆえにさまざまなバリエーションが生まれた。“The Wild Wild West”は西部劇とスパイの組合せで歴史に忠実というわけではなくSF的要素もあった。