【问题标题】:How to test if cmd.exe command exists?如何测试 cmd.exe 命令是否存在?
【发布时间】:2012-09-27 14:44:06
【问题描述】:

例如,在 Windows 7 上,mklink 可从 cmd.exe /C mklink 获得,但在 Windows XP 上则不可用。

除了执行cmd.exe /C mklink 并尝试读取errorlevel 之外,有没有更简单的方法来测试cmd.exe 是否支持某个命令?

谢谢!

【问题讨论】:

  • mklink 不受 cmd.exe 的“支持”,它本身就是一个程序,因此您可以检查它是否存在于 System32 目录中(错误)或检查 Windows 版本(更好)。
  • 程序本身?这与互联网所说的很多内容相矛盾。

标签: batch-file dos cmd


【解决方案1】:

cmdERRORLEVEL 不是命令存在的良好指标,因为如果命令不存在或失败,它会设置为非零值,这可能会导致您的测试失败。

或者,您可以执行以下操作之一:

检查操作系统版本

就像 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 9009ERRORLEVEL>=9009 时有效,因此需要第二个if-statement 来排除ERRORLEVEL>9009 时的情况。

我更喜欢第二种解决方案,因为它预计适用于所有版本的 Windows。

【讨论】:

  • 版本检查似乎是最适合我情况的解决方案。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:
    @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)

    它实际上并不测试给定的命令是否执行,只有当它应该在那里时...
    这只是一个想法,请尝试使其无效,如果您这样做,我会很乐意删除。

    【讨论】:

      【解决方案4】:

      我不久前发布了这个batch script on the SS64 Windows CMD Shell forum。它将 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
      • @user1726251 - 部分算法需要延迟扩展,但如果值包含 ! 且启用了延迟扩展,并且 ! 在路径名中是合法的,则 FOR 变量扩展会损坏。使用了多个 FOR 语句,所以我策略性地使用多个 SETLOCAL 来根据需要获得正确的延迟扩展状态,最后我需要多个 ENDLOCAL 来平衡。
      猜你喜欢
      • 1970-01-01
      • 2011-03-18
      • 2015-04-07
      • 2013-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-04
      • 2020-02-02
      相关资源
      最近更新 更多