【发布时间】:2011-06-14 11:37:25
【问题描述】:
我正在寻找一种简单的方法来测试 Windows 批处理文件中的 PATH 环境变量中是否存在可执行文件。
不允许使用非操作系统提供的外部工具。所需的最低 Windows 版本是 Windows XP。
【问题讨论】:
-
@karlphilip:绝对没有。这里的问题完全不同。
标签: windows batch-file batch-processing
我正在寻找一种简单的方法来测试 Windows 批处理文件中的 PATH 环境变量中是否存在可执行文件。
不允许使用非操作系统提供的外部工具。所需的最低 Windows 版本是 Windows XP。
【问题讨论】:
标签: windows batch-file batch-processing
Windows Vista 和更高版本附带一个名为where.exe 的程序,用于搜索路径中的程序。它的工作原理是这样的:
D:\>where notepad
C:\Windows\System32\notepad.exe
C:\Windows\notepad.exe
D:\>where where
C:\Windows\System32\where.exe
要在批处理文件中使用,您可以使用/q 开关,它只会设置ERRORLEVEL,不会产生任何输出。
where /q myapplication
IF ERRORLEVEL 1 (
ECHO The application is missing. Ensure it is installed and placed in your PATH.
EXIT /B
) ELSE (
ECHO Application exists. Let's go!
)
或打印消息并退出应用的简单(但可读性较差)速记版本:
where /q myapplication || ECHO Cound not find app. && EXIT /B
【讨论】:
for %%X in (myExecutable.exe) do (set FOUND=%%~$PATH:X)
if defined FOUND ...
如果您需要它用于不同的扩展,只需遍历PATHEXT:
set FOUND=
for %%e in (%PATHEXT%) do (
for %%X in (myExecutable%%e) do (
if not defined FOUND (
set FOUND=%%~$PATH:X
)
)
)
可能where 也已存在于旧版 Windows 版本中,但我无权访问,所以我无法确定。在我的机器上也可以使用:
where myExecutable
如果找不到,则返回非零退出代码。不过,在批处理中,您可能还希望将输出重定向到 NUL。
记住
在批处理 (.bat) 文件中解析和在命令行上的解析不同(因为批处理文件有 %0–%9),因此您必须在此处将 % 加倍。在命令行上这不是必需的,所以变量只是%X。
【讨论】:
where myExecutable。
%0–%9),所以你必须把%加倍。在命令行上这不是必需的,所以for 变量只是%x。
这是一个简单的解决方案,它尝试运行应用程序并在之后处理任何错误。
file.exe /? 2> NUL
IF NOT %ERRORLEVEL%==9009 ECHO file.exe exists in path
错误代码 9009 通常表示找不到文件。
唯一的缺点是file.exe 如果找到就会实际执行(在某些情况下这是不可取的)。
【讨论】:
这可以通过参数替换来完成。
%~$PATH:1
这将返回 %1 中可执行文件名的完整路径,否则返回一个空字符串。
这不适用于用户定义的变量。因此,如果可执行文件名不是脚本的参数,那么您需要一个子例程。例如:
call :s_which app.exe
if not "%_path%" == "" (
"%_path%"
)
goto :eof
:s_which
setlocal
endlocal & set _path=%~$PATH:1
goto :eof
【讨论】:
setlocal 的有趣技巧,但for %%X in (myExecutable.exe) do (set FOUND=%%~$PATH:X) 是一种解决方案,for 用作%%~$PATH:X 的解决方法,以避免call 和%~$PATH:1。
对于那些寻找 PowerShell 选项的人。您可以使用Get-Command cmdlet 传递两个项目。首先给出以.\ 为前缀的当前目录位置,然后只给出exe 名称。
(Get-Command ".\notepad", "notepad" -ErrorAction Ignore -CommandType Application) -ne $null
如果在本地或系统范围的路径中找到,则返回 true。
【讨论】:
@echo off
set found=
set prog=cmd.exe
for %%i in (%path%) do if exist %%i\%prog% set found=%%i
echo "%found%"
if "%found%"=="" ....
【讨论】:
for 不够聪明,无法解析 PATH 的内容。例如,它将丢失带有空格的目录。即使您将for /f 与delims=; 一起使用,如果目录包含; 并被引用,它也将无法正常工作。
; 替换为"; ":set quotedPath="%PATH:;="; "%"。
"C:\Folder with; semicolon, quoted" 附加到路径来尝试一下,看看会发生什么。至少在这里它尝试单独处理每个»word«,在某种程度上,这比以前的行为更糟糕。
有时这种简单的解决方案会起作用,您可以在其中检查输出是否符合您的预期。第一行运行命令并获取标准输出的最后一行。
FOR /F "tokens=*" %%i in (' "xcopy /? 2> nul" ') do SET xcopyoutput=%%i
if "%xcopyoutput%"=="" echo xcopy not in path.
【讨论】:
使用命令:powershell Test-Path "你要找的exe"
如果存在则返回 True,否则返回 False。
【讨论】:
Test-Path 只检查指定的路径,即 Test-Path nuget.exe 只有当 nuget.exe 在当前目录中时才会返回 true。如果 nuget.exe 不在当前目录中,它将返回 false,即使它位于 PATH 变量中列出的目录中。在 PowerShell 中 Get-Command 可能会更好(stackoverflow.com/questions/11242368/…),但要考虑到对于 PowerShell,当前目录不在路径中。
(Get-Command ".\notepad", "notepad" -ErrorAction Ignore -CommandType Application) -ne $null,将返回 true。