首页 > 解决方案 > 为什么文件的存在会影响其文件路径在批处理脚本中的解析方式?

问题描述

当与命令一起使用时,我不了解批处理for命令的工作方式/f

我试图循环执行可执行文件的输出。结果证明该可执行文件不存在,这很好。

但是,脚本似乎自发地错误地标记了字符串,而不是得到关于错误路径的预期错误。这让我陷入了一个兔子洞,以为我格式化了 for 循环和/或错误地使用了引号或反引号。

将可执行文件放在该位置可以解决问题,使其看起来像路径字符串标记取决于该路径中实际文件的存在。

为什么下面的批处理文件

@echo off
for /f "usebackq delims=" %%i in ( `"C:\Program Files\BOGUS_PATH\FAKE.exe"`) do (
    rem
)

输出'C:\Program' is not recognized as an internal or external command, operable program or batch file.而不是The system cannot find the path specified.

标签: batch-file

解决方案


首先,我的一个小烦恼,usebackq不需要。更简单且功能等效的命令是

@echo off
for /f "delims=" %%i in ('"C:\Program Files\BOGUS_PATH\FAKE.exe"') do (
    rem
)

唯一usebackq需要的是当您尝试读取文件时,文件路径包含空格等标记分隔符。

for /f "usebackq" %%A in ('"some file.txt"')

所有其他情况都可以使用“正常”形式

for /f %%A in (fileName) do...
for /f %%A in ("string") do...
for /f %%A in ('someCommand') do...

现在回答你的实际问题:-)

文件的存在与否实际上不会改变解析。

首先,您需要了解当您尝试从命令行执行一个不存在的程序时可能出现的错误消息。有三种可能:

1)如果“命令”在第二个位置以外的任何地方都包含冒号,那么您可能会得到以下信息

c:\test\>abc:fake.exe
The filename, directory name, or volume label syntax is incorrect.

c:\test\>abc:\test\fake.exe
The filename, directory name, or volume label syntax is incorrect.

或者有时你会得到下一个可能的错误。关于你收到哪条消息的规则对我来说并不明显,我觉得弄清楚确切的规则并不重要。

2)如果“命令”包含指示路径的反斜杠,并且路径无效,那么您会得到

c:\test\>c:bogus\fake.exe
The system cannot find the path specified.

c:\test\>\bogus\fake.exe
The system cannot find the path specified.

c:\test\>abc:bogus\fake.exe
The system cannot find the path specified.

3)如果找不到可执行文件,并且“命令”不包含路径信息或提供的路径有效,那么你会得到

C:\test\>fake.exe
'fake.exe' is not recognized as an internal or external command,
operable program or batch file.

C:\test>c:\test\fake.exe
'c:\test\fake.exe' is not recognized as an internal or external command,
operable program or batch file.

最后一个难题是为什么"C:\Program Files\BOGUS_PATH\FAKE.exe"给出错误 3) 而不是 2)

如果您从带有引号的命令行执行,那么您会得到预期的结果:

C:\test>"C:\Program Files\BOGUS_PATH\FAKE.exe"
The system cannot find the path specified.

如果从不带引号的命令行执行,则会得到以下预期结果:

C:\test>C:\Program Files\BOGUS_PATH\FAKE.exe
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.

您的脚本包含引号,因此您会期望前者,但您会得到后者。

理解这一点有两个部分。

首先, FOR /F 通过执行来执行命令

C:\WINDOWS\system32\cmd.exe /c "C:\Program Files\BOGUS_PATH\FAKE.exe"

您可能认为您的“命令”被引用了,但 cmd.exe 玩游戏时引用了引号,这是解释的第二部分。cmd.exe 引用规则在帮助中有描述:

c:\test\>help cmd
Starts a new instance of the Windows command interpreter
...
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:

    1.  If all of the following conditions are met, then quote characters
        on the command line are preserved:

        - no /S switch
        - exactly two quote characters
        - no special characters between the two quote characters,
          where special is one of: &<>()@^|
        - there are one or more whitespace characters between the
          two quote characters
        - the string between the two quote characters is the name
          of an executable file.

    2.  Otherwise, old behavior is to see if the first character is
        a quote character and if so, strip the leading character and
        remove the last quote character on the command line, preserving
        any text after the last quote character.

除了最后一个条件外,大多数条件1.都满足- 字符串未指向有效的可执行文件。因此使用了规则,因此命令变为2.

C:\Program Files\BOGUS_PATH\FAKE.exe

现在结果非常合理——“命令”在空间中断。

'C:\Program' is not recognized as an internal or external command,
operable program or batch file.

如果您尝试使用 执行命令FOR /F,并且该命令必须用引号引起来,那么您必须在整个命令周围加上一组额外的引号。

for /f "delims=" %%A in ('""c:\some path\file.exe" "arg 1" arg2"') do ...

但是如果路径或引用的参数中有毒字符,上面会出现问题,因为额外的一组引号会混淆引用。你可以逃脱像毒药一样的角色

for /f "delims=" %%A in ('""c:\some path\file.exe" "this^&that" arg2"') do ...

但我觉得这很尴尬,因为您在命令行中使用的命令与您在FOR /F. 我更喜欢转义额外的封闭引号集,以便在命令行上工作的任何内容也适用于FOR /F.

for /f "delims=" %%A in ('^""c:\some path\file.exe" "this&that" arg2^"') do ...

推荐阅读