我在Windows 7上有一个who.bat,
@echo off
REM This bat searches a file in PATH list to see whether a file can be found.
REM If found, it shows the file's full path.
REM which.bat gcc.exe
REM shows
REM gcc.exe is found: D:\GMU\MinGW2\bin\gcc.exe
REM
REM Note: Filename extension is significant in the search. E.g. If you run
REM which.bat gcc
REM gcc.exe will not be matched.
IF "%1" == "" goto END
IF "%~$PATH:1" == "" (
echo %1 is not found in any directories from PATH env-var.
) ELSE (
echo %1 is found: %~$PATH:1
)
:END
这个蝙蝠很有效,直到我今天发现一个奇怪的行为。
有一个文件O:\temp\pfiles (x86)\mystuff.txt
,PATH有内容:
PATH=O:\temp\pfiles (x86);D:\CmdUtils
正在运行which mystuff.txt
,我得到非常严重输出:
\mystuff.txt was unexpected at this time.
经过一番探讨之后,我发现目录名中的(x86)
会导致问题。要解决此问题,我必须向echo
添加引号,如下所示:
echo %1 is found: "%~$PATH:1"
此类调整的缺点是显而易见的:报价打印到屏幕上,这在程序员看来并不总是需要。
任何人都可以帮助解释这种奇怪的行为吗?
我发现这个问题,因为在我的真实环境中,我在PATH中有一些像C:\Program Files (x86)\Common Files\NetSarang
这样的路径,它们表现出完全相同的症状。
答案 0 :(得分:8)
MS Dos是非常简单的shell实现,因为我已经发现一个DOS命令行的解释分为两个阶段:
在这种情况下,您的命令行:
IF "%~$PATH:1" == "" (
echo %1 is not found in any directories from PATH env-var.
) ELSE (
echo %1 is found: %~$PATH:1
)
将被解释为:
IF "O:\temp\pfiles (x86)\mystuff.txt" == "" (
echo mystuff is not found in any directories from PATH env-var.
) ELSE (
echo mystuff.txt is found: O:\temp\pfiles (x86)\mystuff.txt
)
现在我们可以注意到(x86)
中的问题,即解释器会以某种方式看到这种情况 - 首先)
关闭其他声明:
) ELSE (
echo mystuff.txt is found: O:\temp\pfiles (x86
)\mystuff.txt
)
解决方案:在所有可能存在问题的变量周围加上“”。
我通常在整个echo命令内容中加上引号,例如:
echo "%1 is found: %~$PATH:1"
答案 1 :(得分:4)
现在问题很明显(来自Michael Burr和Robert Lujo),我试图展示一个解决方案。
您需要引号,但不想显示它们。
延迟扩展后,右括号无害
setlocal EnableDelayedExpansion
IF "%~$PATH:1" == "" (
echo %1 is not found in any directories from PATH env-var.
) ELSE (
set "found=%~$PATH:1"
echo %1 is found: !found!
)
或只是消失的报价
IF "%~$PATH:1" == "" (
echo %1 is not found in any directories from PATH env-var.
) ELSE (
for %%^" in ("") do (
echo %1 is found: %%~"%~$PATH:1
)
)
答案 2 :(得分:2)
我可以猜到一个解释(虽然不是一个有用的解释):cmd.exe的解析器不是很聪明 - 它被%~$PATH:1
中的parens弄糊涂了 - 当它扩展变量并看到{{ 1}}字符,它假定它是)
行的闭包。 (我认为它对扩展中的) ELSE (
字符没有任何作用,因为它们仅在命令开始时很重要。)
您可以通过确保包含')'的扩展不在(
命令分组中,或者引用它(如您找到的)来解决此问题。由于您不需要引号,因此其他解决方法可能如下所示:
(...)
这很难看,但这与cmd.exe脚本有关。