6

我在 Windows 7 上有一个 which.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)in 目录名称导致了问题。要解决方法,我必须在 中添加引号echo,如下所示:

echo %1 is found: "%~$PATH:1"

这种调整的缺点是显而易见的:引号被打印到屏幕上,这在程序员看来并不总是需要的。

谁能帮助解释这种奇怪的行为?

我发现这个问题是因为在我的真实环境中,我有一些类似C:\Program Files (x86)\Common Files\NetSarangPATH 的路径,它们表现出完全相同的症状。

在此处输入图像描述

4

3 回答 3

8

MS Dos 是一个非常简单的 shell 实现,正如我发现的那样,一个 DOS 命令行的解释分为两个阶段:

  1. 评估当前行中的变量
  2. 评估命令行的解释

在这种情况下,您的命令行:

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 语句:

) ELSE (
      echo mystuff.txt is found: O:\temp\pfiles (x86
)\mystuff.txt
)

解决方案:将 "" 放在所有可能有问题的变量周围。

我通常在整个 echo 命令内容周围加上引号,例如:

echo "%1 is found: %~$PATH:1"
于 2013-05-13T09:49:24.937 回答
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
      )
    )
于 2013-05-13T10:13:54.507 回答
2

我可以猜到一个解释(虽然不是一个有用的解释):cmd.exe 的解析器不是很聪明——它被括号中的括号弄糊涂了%~$PATH:1——当它扩展变量并看到)字符时,它假定它是 closig 括号线) ELSE (。(我认为它对扩展中的角色没有任何作用,(因为这些仅在命令开头才有意义)。

您可以通过确保可以包含“)”的扩展不在(...)命令分组内,或者它被引用(如您所见)来解决此问题。由于您不想要引号,因此其他解决方法可能如下所示:

@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 (
      call :printfound %1
    )

goto END

:printfound
echo %1 is found: %~$PATH:1
goto :eof

:END

这很丑陋,但这就是你必须用 cmd.exe 脚本做的事情。

于 2013-05-13T09:49:32.013 回答