Windows では、実行可能ファイルの拡張子が環境変数 PATHEXT
に入っているので、PATH
と PATHEXT
を利用すれば which
コマンドが作れる。
PATHEXT
について
PATHEXT
にはセミコロン区切りで実行可能ファイルの拡張子が入っている。
C:\Users\foo>echo %PATHEXT%
.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
拡張子は格納順に優先度が高いため、上記の場合、foo.exe
と foo.bat
が同じフォルダに存在する場合、foo
を実行すると foo.exe
が実行される。
which
コマンドの実装
インタフェースは Linux の which
コマンドと同様にする。
SYNOPSIS
which [-a] filename
OPTIONS
-a 見つかった全ての実行可能ファイルを表示する。
EXIT STATUS
0 指定した全てのコマンドが見つかった
1 指定したいずれかのコマンドが見つからなかった
2 不正なオプションを指定した
-a
オプションを指定すると、環境変数 PATH
に存在する全ての実行可能ファイルを出力する。また、複数のコマンドを同時に指定することもできる。
以下の内容の which.cmd
をパスの通ったフォルダに置く。
@echo offsetlocal set ALL=0 set NOTFOUND=0 set OPT=%~1 if "%OPT%"=="" exit /b if "%OPT%"=="-a" ( set ALL=1 shift ) else if "%OPT:~0,1%"=="-" ( echo Illegal option %OPT% echo Usage: which [-a] args exit /b 2 ) if "%~1"=="" exit /b :LOOP set COMMANDS=;%PATHEXT% call set COMMANDS=%%COMMANDS:;= %~1%% set COMMANDS=(%COMMANDS:~1%) for %%i in %COMMANDS% do ( if exist %%~$PATH:i ( echo %%~$PATH:i if %ALL%==0 goto :NEXT ) ) set NOTFOUND=1 :NEXT shift if not "%~1"=="" goto LOOP if %NOTFOUND%==1 exit /b 1endlocal```
```cmd:実行結果
C:\Users\foo>which notepad ipconfig
C:\Windows\System32\notepad.exe
C:\Windows\System32\ipconfig.exe
実装方法
実装のポイントは、セミコロンで区切られた PATHEXT
の各拡張子を取り出す方法。通常のプログラミング言語のように、".exe;.bat".split(";")
などとして、拡張子をリストに分割できそうにないので、別の方法を考える。
C:\Users\foo> for %i in (foo.exe foo.bat) do echo %i
foo.exe
foo.bat
のように、 for
コマンドを使用することでループは実現できるので、(foo.exe foo.bat)
のような文字列を作ればよい。
set COMMANDS=;%PATHEXT%
=> ";.EXE;.BAT"
call set COMMANDS=%%COMMANDS:;= %~1%%
=> " foo.EXE .foo.BAT"
set COMMANDS=(%COMMANDS:~1%)
=> "(foo.EXE foo.BAT)"
で、変数 COMMANDS
に、for
で回すための文字列を作っている。