Windows .bat文件,%〜$ PATH:1引号问题

时间:2013-05-13 09:03:18

标签: windows batch-file cmd

我在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.

enter image description here

经过一番探讨之后,我发现目录名中的(x86)会导致问题。要解决此问题,我必须向echo添加引号,如下所示:

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

此类调整的缺点是显而易见的:报价打印到屏幕上,这在程序员看来并不总是需要。

任何人都可以帮助解释这种奇怪的行为吗?

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

enter image description here

3 个答案:

答案 0 :(得分:8)

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

  1. 评估当前行中的变量
  2. 对评估命令行的解释
  3. 在这种情况下,您的命令行:

    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脚本有关。