« べた | トップページ | テレビ番組等感想 その 131 »

2008年9月15日 (月)

Yash 2 その 54: シェルのコマンド検索

コマンドを入力して実行したときに、そのコマンドが実際にどこにあるかを探し出すのはシェルの仕事である (少なくとも POSIX 準拠シェルでは)。コマンドの検索は、PATH 変数で指定した各ディレクトリからコマンド名と同じ名前の実行可能なファイルを探し出すことで行う。しかし組込みコマンドや関数も考慮すると話はもっと複雑になる。以下に、POSIX が定めるコマンド検索の方法を説明しよう。

コマンドを実行する際、まずシェルはコマンド名にスラッシュが入っているかを調べる。スラッシュが入っていれば、そのコマンド名をそのまま絶対パスまたは相対パスとみなしてプログラムを起動する。もしそのパスに実行可能なファイルがなければエラーとなる。スラッシュが入っていなければ、以下のようにコマンドの検索を行うことになる。

コマンドの検索は、そのコマンドが特殊組込みコマンドかどうかを調べることから始まる。特殊組込みコマンドとは POSIX で決められたごく一部の組込みコマンドのことで、.exit などがこれに該当する。コマンドが特殊組込みであることが分かったら、ただちにそれが実行される。

コマンドが特殊組込みでなければ、次にシェルはそれが関数として定義済みかどうか調べる。ユーザが定義した関数があれば、ただちにそれが実行される。特殊組込みかどうかを調べた後に関数かどうかを調べるということは、特殊組込みは関数によって上書きできないということを意味する。またユーザが定義したものではない関数はここでは無視する。

コマンドが関数でもなければ、続いてそれが準特殊組込みコマンド――とここでは呼んでいるが、POSIX で正式に定義された用語ではない――かどうかを調べる。準特殊組込みだと分かったら、ただちにそれが実行される。fgcd などが該当する。

準特殊組込みでもなければ、シェルは PATH 変数に指定した各ディレクトリからコマンドを検索する。どのディレクトリにも、実行しようとしているコマンドと同じ名前の実行可能なファイルがなければ、エラーとなる。実行可能ファイルが見つかれば、それがコマンドとして実行される。ただし、そのコマンドが組込みコマンドならばその組込みコマンドが実行される。また組込み関数があればその関数が実行される。

以上が POSIX が定めるコマンドの検索方法である。組込みコマンド 3 種類に分けられていて扱い方が異なっているのがややこしい。とくに特殊組込みでも準特殊組込みでもない組込みコマンド (以下その他の組込みと呼ぶ) や組込み関数は、PATH 検索で実行可能ファイルが見つかった場合にしか実行されない。これにより、その他の組込みコマンドや組込み関数と通常の外部コマンドとの実質的な違いはなくなる (パスが通っているかによって起動できるかどうかが決まるという点で)。

しかしこれに従うと、シェルの独自の組込みコマンドが使えなくなってしまう (普通それらは独立した実行可能ファイルとしては存在しないので)。このため yash では非 POSIX 準拠モードで動作する際にはその他の組込みも準特殊組込みと同様に扱う。

コマンド検索に関しては、それをいつ行うかも問題となる。POSIX の定めによれば、コマンドは以下の順序で実行することになっている。

  1. コマンドや引数内のパラメータ展開などを展開する。
  2. リダイレクトを行う。
  3. コマンドに付された変数の代入を行う。
  4. コマンド検索を行いコマンドを実行する。

つまり、コマンド検索はコマンドを実行する直前に行うことになっている。

ところが実際には、コマンド検索をそのタイミングで行うのはほぼ無理なのである。というのも、外部コマンドに対するリダイレクトや変数代入はシェルそのものの状態に影響してはならないことになっているので、シェルは先に分身 (fork) して、それからリダイレクトと代入を処理し、最後にコマンドを実行 (exec) するという手順を踏まざるを得ない。一方組込みコマンドは分身せずにシェルが直接実行するので、先ずシェルは分身すべきかどうかを判断する必要がある。すなわち、シェルは最初にコマンド検索を行ってコマンドの種類を決定しなければならない。

しかしこれでは、本来コマンド検索の前に行うべき変数代入をコマンド検索の後に行うことになる。従って、そのコマンドが PATH 変数への代入を伴っている場合、本来の代入後のパスではなく代入前のパスで検索を行ってしまう。この時、実行可能ファイルが代入前の PATH には見つからなかったが代入後の新しい PATH では見つかり、かつそのコマンドがその他の組込みの場合、本来シェル本体で実行すべき組込みコマンドを分身後のサブシェルで実行することになってしまう。

この問題を回避しようとすると、リダイレクトや代入を処理してからコマンド検索を行って分身するかどうかを決めるしかなくなるが、そうすると分身後に元のシェルをリダイレクトや代入を行う前の状態まで復元する処理が必要となり、全体の処理速度が大きく低下するとともに処理も複雑になる。

Yash では、この問題への対処は諦めることにした。Zsh も諦めている (単にたまたまそうなっているだけかもしれないが)。Bash, ksh, dash はその他の組込みを常に準特殊組込みと同様に扱っているので、そもそも規格に反している。

|

« べた | トップページ | テレビ番組等感想 その 131 »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/169172/42477504

この記事へのトラックバック一覧です: Yash 2 その 54: シェルのコマンド検索:

» Yash 2 その 122 [まじかんと雑記]
Autocd オプションを廃止してより汎用的な command-not-found ハンドラを導入する準備としてコマンド検索と実行のしかたを変更した。 [続きを読む]

受信: 2009年7月27日 (月) 09時45分

« べた | トップページ | テレビ番組等感想 その 131 »