首先,我有一个小抱怨,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) 如果找不到可执行文件,且“command”没有包含路径信息或提供的路径是有效的,则会出现以下错误:
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
现在的结果非常清晰易懂 - "command" 在空格处被截断。
'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 ...
for /f "delims=" %%i in ("C:\Program^ Files\BOGUS_PATH\FAKE.exe") do echo %%i
。(请不要问我为什么...) - Stephan'
:for /f "delims=" %%i in ('"C:\Program^ Files\BOGUS_PATH\FAKE.exe"') do echo %%i
- Stephanc:\program^ files\bogus_path\fake.exe
。这是我见过的第一个可以这样转义标记分隔符的情况。但如果删除前面的“c:”,转义就不起作用了,在所有情况下都是我所期望的。今天我学到了东西,谢谢。 - dbenhamfor /f "delims=" %%I in ('c:\program^^^ files\bogus_path\fake.exe') do ...
,因为有两轮解析,所以你需要转义转义符。 - dbenham