在批处理脚本中实现“哪个”命令

我试图制作一个类似于which脚本的脚本。 所以我想检查这个命令是内部的还是外部的,或者两者兼而有之。 我试图执行程序,但是当程序(例如.exe)不正确我的程序退出时出现错误,所以我试图打电话给这个程序的help 。 但是现在,如果我尝试检查示例echo并在我当前的目录中有echo.exe我得到它是外部命令,但不是内部。 所以我的问题是如何做到这一点。 如何检查这个程序是内部的还是外部的。 谢谢。 这是我的代码:

 @echo off setlocal enabledelayedexpansion if "%1"=="" goto help :start if not "%1"=="" ( shift if "%1"=="/?" goto help goto :start ) set arg=%* for %%a in ("%pathext:;=" "%") do ( echo %arg%|findstr /E /I %%a >nul rem If file was given with extension if not ERRORLEVEL 1 goto with_rashr ) set ext=0 for %%a in ("%pathext:;=" "%") do ( if EXIST "%CD%\!arg!%%~a" ( echo This is an external command: %CD%\!arg!%%~a set ext=1 goto :internal ) ) for %%G in ("%path:;=" "%") do ( for %%a in ("%pathext:;=" "%") do ( if EXIST "%%~G\!arg!%%~a" ( echo This is an external command: %%~G\!arg!%%~a set ext=1 goto :internal ) ) ) goto :internal :with_rashr echo Command with extension was given if EXIST "%CD%\!arg!" ( echo This is an external command: %CD%\!arg! set ext=1 goto :internal ) for %%G in ("%path:;=" "%") do ( if EXIST "%%~G\!arg!" ( echo This is an external command: %%~G\!arg! set ext=1 goto :internal ) ) :internal set PATH= rem set PATH=%PATH%;%CD% help %arg% >nul 2>&1 rem set error_check=%ERRORLEVEL% rem echo %error_check% rem %arg% /? rem ERRORLEVEL 9009 when a batch attempts to execute a program that is not found. rem echo %ext% if ERRORLEVEL 9009 ( echo We couldn't execute command if "%ext%"=="0" ( echo This is not a command ) endlocal goto :EOF ) if "%ext%"=="1" ( if ERRORLEVEL 0 ( echo This is also an internal command ) endlocal goto :EOF ) echo This is internal command endlocal goto :EOF :help echo Like which echo Shows if this command external or internal 

Solutions Collecting From Web of "在批处理脚本中实现“哪个”命令"

很好的问题,解决这个问题令人惊讶。

我以为我在http://ss64.org/viewtopic.php?pid=5752#p5752有一个很好的工作版本,在这个版本中,我回答了另一个人试图做基本相同的事情。 但是在读完你的问题之后,我意识到我的旧“解决方案”会遭遇同样的问题 – 如果碰巧在路径中某个具有相同根名称的exe文件,它会错误地将内部命令作为外部命令报告。

我第一次检查是否可以找到一个外部命令,如果没有,那么我认为任何HELP知道的命令都是内部命令。

我想我现在有一个工作版本。

我检查命令是否是第一个内部命令,使用与您尝试的类似的技巧。 我添加了一些曲折。

  • 我取决于%temp%文件夹中的空文件夹(如果它不存在,则创建它)
  • 我担心命令注入,所以我确认在我进行内部测试之前,命令只包含字母。
  • (CALL )命令是清除ERRORLEVEL的快捷方法

据我所知,如果给出一个参数/?每个内部命令都会打印出帮助信息/? 。 如果该命令不是内部的,那么它将无法执行并将ERRORLEVEL设置为9009,因为PATH是空的,而当前目录是空的。

 ::WHICH CommandName [ReturnVar] :: :: Determines the full path of the file that would execute if :: CommandName were executed. :: :: The result is stored in variable ReturnVar, or else it is :: echoed to stdout if ReturnVar is not specified. :: :: If no file is found, then an error message is echoed to stderr. :: :: The ERRORLEVEL is set to one of the following values :: 0 - Success: A matching file was found :: 1 - CommandName is an internal command :: 2 - No file was found and CommandName is not an internal command :: 3 - Improper syntax - no CommandName specified :: @echo off setlocal disableDelayedExpansion set "file=%~1" setlocal enableDelayedExpansion if not defined file ( >&2 echo Syntax error: No CommandName specified exit /b 3 ) :: test for internal command echo(!file!|findstr /i "[^abcdefghijklmnopqrstuvwxyz]" >nul || ( set "empty=!temp!\emptyFolder" md "!empty!" 2>nul del /q "!empty!\*" 2>nul >nul setlocal pushd "!empty!" set path= (call ) !file! /? >nul 2>nul if not errorlevel 9009 ( >&2 echo "!file!" is an internal command popd exit /b 1 ) popd endlocal ) :: test for external command set "noExt=" if "%~x1" neq "" if "!PATHEXT:%~x1=!" neq "!PATHEXT!" set noExt=""; set "modpath=.\;!PATH!" @for %%E in (%noExt%%PATHEXT%) do @for %%F in ("!file!%%~E") do ( setlocal disableDelayedExpansion if not "%%~$modpath:F"=="" if not exist "%%~$modpath:F\" ( endlocal & endlocal & endlocal if "%~2"=="" (echo %%~$modpath:F) else set "%~2=%%~$modpath:F" exit /b 0 ) endlocal ) endlocal >&2 echo "%~1" is not a valid command exit /b 2