如何测试cmd.exe命令是否存在?

4
作为例子,在Windows 7中,mklink可从cmd.exe /C mklink使用,但在Windows XP中不行。
除了执行cmd.exe /C mklink并尝试读取errorlevel之外,是否有更简单的方法来测试cmd.exe是否支持命令?
谢谢!

2
mklink不是由cmd.exe“支持”的,它本身就是一个程序,因此您可以检查它是否存在于System32目录中(不好),或者检查Windows版本(更好)。 - Adriano Repetti
这是一个程序本身吗?这与互联网上的很多说法相矛盾。 - E.Beach
4个回答

3
< p > ERRORLEVEL 不是判断命令是否存在的好指标,因为当命令不存在或失败时,它被设置为非零值,这可能会干扰测试。

另外,你可以选择以下任一方法:

检查操作系统版本

像Adriano在评论中建议的那样,可以通过以下方式检查Windows版本:

set mklink_supported=true
ver | find "XP" >nul 2>&1 && set mklink_supported=false

或者像这样:
set mklink_supported=false
echo %vers% | find "Windows 7" >nul 2>&1 && set mklink_supported=true

然后:

if %mklink_supported%==false (
    echo 'mklink' is not supported on this operating system.
)

或者类似这样的内容。但是,您需要确保处理所有必要的操作系统版本。

测试命令并检查ERRORLEVEL

或者,您可以尝试直接运行mklink。如果找不到它,则将ERRORLEVEL设置为9009

@echo off
mklink >nul 2>&1
if errorlevel 9009 if not errorlevel 9010 (
    echo 'mklink' is not supported on this operating system.
)

请注意,这里有两个if语句。if errorlevel 9009是在ERRORLEVEL>=9009时才会执行,所以第二个if语句是必须的,以排除ERRORLEVEL>9009的情况。
我更喜欢第二种解决方案,因为它预计可以在所有版本的Windows上运行。

1
版本检查似乎是最适合我情况的解决方案。 - E.Beach

1

要查找可执行文件,您可以在 for 循环中使用变量扩展:

setlocal EnableDelayedExpansion
set found=no
for %%f in (mklink.exe) do if exist "%%~$PATH:f" set found=yes
echo %found%
endlocal

1
@echo off 
(for /f %%F in ('help') do echo '%%F ')|findstr /i /c:"%1 " 2>&1 >nul && echo Supported || echo Not supported 

这取决于一个事实,即help 似乎包含相当完整的内部命令列表(以及相当多的外部命令)。它期望命令名称作为其参数(isSupported.bat command_name)。

它实际上并不测试给定命令是否执行,只是测试它是否应该存在...
这只是一个想法,请尝试否定它,如果您这样做,我会很高兴删除它。


0

我一段时间前在SS64 Windows CMD Shell论坛上发布了这个批处理脚本。它将wmz和Ansgar Wiechers答案中的思路结合成一个方便的包。

它试图在PATH中的某个位置定位给定的可执行文件,如果没有找到,则搜索HELP。如果缺少HELP覆盖的标准实用程序,则可能会给出错误结果和一些丑陋的错误消息。

::WHICH.BAT  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 - No file was found and 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"
if not defined file (
  >&2 echo Syntax error: No CommandName specified
  exit /b 3
)
set "noExt="
setlocal enableDelayedExpansion
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
>nul help %~1 && (
  >&2 echo "%~1" is not a valid command
  exit /b 2
)
>&2 echo "%~1" is an internal command

为什么在for循环中使用3个endlocal? endlocal & endlocal & endlocal - Why
@user1726251 - 算法的某些部分需要延迟扩展,但如果启用了延迟扩展且值包含 !,则 FOR 变量扩展会出现错误,而 ! 在路径名中是合法的。由于使用了多个 FOR 语句,因此我策略性地使用多个 SETLOCAL 来获取所需的正确延迟扩展状态,并在最后需要多个 ENDLOCAL 来平衡。 - dbenham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接