WHICHコマンド (6) 〜最後〜

最終回は残りの部分。1回目の仕様で書いた、
(5) PATHをサーチして見つけた最初の実行ファイルのフルパスを環境変数「 _ 」にセットする
の部分であるが、最後なので全文を掲載する。例によってインデントは2バイト空白なのでコピーペーストする人は注意。

PATHをサーチして見つけた部分ということで、20-22行および28-30行である。最初かどうかは、最初に02行で _ を未定義にしておいて、if not definedで調べている。endlocal/setlocalについては7/24:setlocalしたスクリプトから外部の環境変数をセットも参照のこと。

このスクリプトで使用しているローカル変数はBLTだけであるが、12行目の%BLT%の置換は08行のfor文の時点で行われるため、08行目の後にendlocalを1回だけ書いておいても良い。実は2回目以降のsetlocalは不要である。

01 @echo off
02 set _=
03 setlocal
04 set BLT=ASSOC BREAK CALL CD CHDIR CLS COLOR COPY DATE DEL DIR ECHO
05 set BLT=%BLT% ENDLOCAL ERASE EXIT FOR FTYPE GOTO IF MD MKDIR MOVE
06 set BLT=%BLT% PATH PAUSE POPD PROMPT PUSHD RD REM REN RENAME RMDIR
07 set BLT=%BLT% SET SETLOCAL SHIFT START TIME TITLE TYPE VER VERIFY VOL
08 for %%X in (%*) do (
09  for /f "delims=" %%A in ('DOSKEY /MACROS') do (
10   for /f "delims==" %%B in ("%%A") do if /i "%%B" == "%%X" echo %%A
11  )
12  for %%A in (%BLT%) do if /i "%%X" == "%%A" echo %%X cmd.exe builtin
13  if not "%%~xX" == "" if exist %%X if not exist %%~sX\NUL echo %%~X
14  for %%S in (%PATHEXT%) do if exist %%X%%S if not exist %%~sX%%S\NUL echo %%~X%%S
15  if "%%~X" == "%%~nxX" ( 
16   for %%P in ("%PATH:;=";"%") do (
17    if not "%%~xX" == "" if exist %%P\%%X (
18     for /f "delims=" %%W in ("%%~P\%%~X") do if not exist %%~sW\NUL (
19      echo %%~P\%%~X
20      endlocal
21      if not defined _ set _=%%~P\%%~X
22      setlocal
23     )
24    )
25    for %%S in (%PATHEXT%) do if exist %%~sP\%%X%%S (
26      for /f "delims=" %%W in ("%%~P\%%~X%%S") do if not exist %%~sW\NUL (
27       echo %%~P\%%~X%%S
28       endlocal
29       if not defined _ set _=%%~P\%%~X%%S
30       setlocal
31      )
32    )
33   )
34  )
35 )
36 endlocal
37 if not defined _ goto :eof
38 if not "%_%" == "%_: =%" set _="%_%"

37行で、_ が未定義か判断してそうなら終了している。
38行で、_ に空白が含まれているかを判断して、そうなら " " で囲っている。空白を含むかの判断は、: 修飾子で空白を削除して元の値と等しいかどうかで行っている。

この2行は、
if defined _ if not "%_%" == "%_: =%" set _="%_%"
と1行で書けそうである。しかし、環境変数が未定義のときの : 修飾子の振る舞いからこれは構文エラーとなる。遅延環境変数を使って、
if defined _ if not "!_!" == "!_: =!" set _="!_!"
と書けば問題ないが、スクリプト中で遅延を有効にできるのはsetlocalコマンドしかないので、かえって長くなってしまう。

環境変数未定義時の : 修飾子の振る舞いはいまいちよくわからないので、いずれ調べてみる。

以上で連載は終わりである。

いよいよネタが無いので、ネタ求むトリビアの種と違って賞品は出ないが。