WHICHコマンド (4) 〜コマンド探索(前編)〜

4回目は、PATH環境変数を使ったサーチの前にcmd.exeが行う実行ファイルチェックの部分について。
このケースには、
(1) コマンドとして入力された文字列がそのまま実行ファイル名である場合
(2) コマンドとして入力された文字列にPATHEXTの内容を付加したものが実行ファイル名である場合
の2パターンがある。
(1)のパターンの場合には、入力された文字列に拡張子が含まれていることが必要である。ファイル名の部分にピリオドが含まれていない場合は、そのファイルが存在しても実行されない。具体的に言うと、カレントディレクトリにabcというファイルが存在したとして、abcと入力してもフルパスで入力しても実行されない。一方、abc.deというファイルが存在したら、abc.deと入力すると実行される。ここで、「実行される」とは、

?? は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。

というメッセージが表示されないという意味である。場合分けすると、
(a) 実行可能プログラムである場合
(b) 拡張子が何らかの実行可能プログラムに関連付けられた(ドキュメント)ファイルである場合
(c) 拡張子が実行可能プログラムに関連付けられていないため実行プログラム指定を求めるダイアログが表示される場合
の3パターンがある。

入力した文字列のファイルが存在しない場合には、(2)のパターンとなり、PATHEXT環境変数にセットされた拡張子が順に付加されて(1)の場合と同じ実行ファイルのチェックが行われる。このとき、元の文字列に拡張子があってもその後ろに付加され、この付加されたほうが新たな拡張子となる。例えば、aaa.jpgの入力に対して、aaa.jpgが存在せず、aaa.jpg.comが存在すればそれが実行される。

いずれのパターンの場合でも、入力された文字列に\が含まれていない場合はカレントディレクトリのファイルがチェックされる。これがunixと大きく違う点だ。unixの場合、トラップにかからないよう、PATH環境変数にはカレントディレクトリを含めないのが常識となっているが、windowsの場合は(DOSの時代から)、そんな考慮など知らん顔でまずカレントディレクトリがチェックされてしまう。カレントディレクトリのファイルを実行する際、unixでの./a.outのように先頭に . を付けなければいけないのを嫌ってのことであろう。セキュリティより見た目の利便性を優先するのがMicrosoftの伝統だから一貫性はある。

さて最後に上記をチェックするスクリプトである。全体については2回目を参照。そこで書いた【カレントディレクトリおよびパス指定時のサーチ】というのが以下である。入力された文字列は、%%Xに入っている。

if not "%%~xX" == "" if exist %%X if not exist %%~sX\NUL echo %%~X
for %%S in (%PATHEXT%) do if exist %%X%%S if not exist %%~sX%%S\NUL echo %%~X%%S

if notとかあってわかりにくいので、最初の行を日本語で書くと、
「もし、%%Xに拡張子があって、かつ、%%Xの実体が存在して、かつ、それがディレクトリでなければ、それが実行される」
ディレクトリかどうかのチェックは、7/28:ディレクトリかどうかの判断およびその翌日の続編を参照。

次の行は、%%Xの後にPATHEXTの内容を順に付加した文字列に対して最初の行と同じチェックを行う。
実行ファイル名の表示の際には入力された文字が" "で囲まれていてもそれを~修飾子ではずして表示している。これは好みの領域である。

なんか、長くなってしまった。次回はいよいよ、PATH環境変数にセットされたディレクトリのサーチである。

つづく