【続々々々】ディレクトリかどうかの判断〜whichコマンドの改訂版

以前の記事において、

昨日の記事に対し、

私は、dir "対象" /a:d してみて errorlevel を見ます。 NUL に頼るより確実では?

というコメントを頂いた。ただ、if existで一気にチェックできるコンパクトさは捨てがたい。ということで、もう少しあがいてみました。

ということで、

if exist "%%A" if not exist "%%A\" echo 普通のファイル

という方法を取った。しかし、|| を使うと、コンパクトさを損なわずに dir を使う方法も取れる。

if exist "%%A" dir /b/ad "%%A" >NUL 2>NUL||echo 普通のファイル

である。/b は必須ではないがわずかに速くなる。これと元の方式を使った which.bat の処理時間を比べてみた。
exist 方式が 0.2 秒で、dir 方式が 0.4 秒である。時間自体は PATHPATHEXT の要素数に依存するがいずれにしても exist 方式のほうが速いようだ。
わずかの差ではあるが、0.2 秒だと瞬間的に終わるのに対して、0.4 秒だとちょっともたつく感じである。PenIII/650MHzでの結果なので、もっと速いCPUだと dir 方式でも気にならないかもしれない。アンドキュメントの機能を使わないわけだし。
私の場合は当面 exist 方式を使い続ける。また、同じような処理が4回出てくるのでこれをサブルーチンにしてみたが、処理時間が 0.8 秒とかなり長くなる。ソースは見やすくなるがこれではもたつきが気になるので、サブルーチン化はしないことにする。
高速CPUの人は、dir 方式 & サブルーチン方式のほうがソースが見やすいだろう。
うーん、PCの買い替え時かなぁ。。。高速CPU使用者向けに一応紹介する。

@echo off
for %%X in (%*) do (
 for /f "delims=" %%A in ('DOSKEY /MACROS') do (
  for /f "delims==" %%B in ("%%A") do if /i "%%B" == "%%X" echo %%A
 )
 for %%A in (ASSOC BREAK CALL CD CHDIR CLS COLOR COPY DATE DEL DIR ECHO
  ENDLOCAL ERASE EXIT FOR FTYPE GOTO IF MD MKDIR MOVE PATH PAUSE POPD
  PROMPT PUSHD RD REM REN RENAME RMDIR SET SETLOCAL SHIFT START TIME
  TITLE TYPE VER VERIFY VOL) do if /i "%%X" == "%%A" echo %%X cmd.exe builtin
 if not "%%~xX" == "" call :sub "%%~X"
 for %%S in (%PATHEXT%) do call :sub "%%~X%%S"
 set _=
 if "%%~X" == "%%~nxX" (
  for %%P in ("%PATH:;=";"%") do (
   if not "%%~xX" == "" call :sub "%%~P\%%~X"
   for %%S in (%PATHEXT%) do call :sub "%%~P\%%~X%%S"
  )
 )
)
if not defined _ goto :eof
if not "%_%" == "%_: =%" set _="%_%"
goto :eof
:sub
if exist "%~1" dir /b/ad "%~1" >NUL 2>NUL||(echo %~1&if not defined _ set "_=%~1")

以前書いたものからは、seltlocal を使わないなど若干改善してある。

2004-09-25 誤りがあったので少し修正