与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.
吗?
答案 0 :(得分:4)
首先,不需要我的宠儿,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 ...
答案 1 :(得分:3)
FOR 是Windows命令处理器cmd.exe
的内部命令。使用带有选项/F
的命令 FOR 和要执行的命令,结果以%ComSpec% /c
和指定的命令行作为进一步的参数开始,并在其中运行另外一个命令进程背景。
处理 STDOUT 的所有输出均由执行命令 FOR 的批处理文件的当前命令进程捕获,并在终止后由 FOR 处理另外{@ {1}}一行一行地开始。
用于处理另外启动的命令过程的 STDERR 的输出被重定向为处理当前命令过程的 STDERR ,导致在情况下将其显示在控制台窗口中STDERR 既不在额外启动的命令过程中,也不在当前命令过程中重定向到其他句柄,文件或设备 NUL 。
使用免费的Sysinternals(Microsoft)工具Process Monitor可以看到这一点。
cmd.exe
,这是运行 Process Monitor 所必需的。向上滚动到捕获的文件系统活动列表的开头,然后查找其中显示具有与第一个进程标识符不同的进程标识符的Procmon.exe
的行。具有不同PID的第二个cmd.exe
是由 FOR 启动的Windows命令处理器实例。
右键单击第二个cmd.exe
,在属性的上下文菜单中单击鼠标左键,选择选项卡 Process ,然后查看命令行 >显示:
cmd.exe
好的。因此,我们现在知道 FOR C:\Windows\system32\cmd.exe /c "C:\Program Files\BOGUS_PATH\FAKE.exe"
在运行命令以捕获该命令的输出时分别做了什么。关闭属性窗口。
查看列表,可以看到第二cmd.exe
进行了哪些文件系统访问,以找到在指定目录和现有目录中不存在的指定可执行文件。接下来,它也搜索cmd.exe
,也没有结果文件。
第一个参数字符串现在在参数分隔符上拆分,该分隔符属于空格字符,例如逗号或等号。因此,第一个参数字符串C:\Program Files\BOGUS_PATH\FAKE.exe.*
再次被参数分隔,导致现在将C:\Program Files\BOGUS_PATH\FAKE.exe
解释为第一个参数字符串。
C:\Program
检查目录路径cmd.exe
之前是否存在现在仅C:\
的目录路径。
接下来检查是否存在与模式C:\Program Files\BOGUS_PATH
匹配的文件,该文件不返回任何此类文件。然后C:\Program.*
检查是否存在文件cmd.exe
,该文件又没有该文件。
第二秒钟C:\Program
放弃寻找可以执行的文件并输出错误消息。
由于空间不足,无法按要求用双引号将完整路径指定为可执行文件确实令人困惑
“ C:\ Program Files \ BOGUS_PATH \ FAKE.exe”未被识别为内部或外部命令
可操作的程序或批处理文件。
这是预期的,但输出是错误消息:
'C:\ Program'不被识别为内部或外部命令
可操作的程序或批处理文件。
我认为,例如,如果用户使用命令(参数)运行cmd.exe
,则使用参数分隔符再次解析第一个参数字符串(如果找不到要执行的文件)
cmd.exe
代替
"C:\Programs\MyApplication.exe C:\Temp\FileToProcess.txt"
所以问题是:
这个自动参数解析好还是不好?
嗯,这很难回答。如dbenham在his answer中所述,它至少以某种方式在"C:\Programs\MyApplication.exe" "C:\Temp\FileToProcess.txt"
的帮助下得到了记录。
答案 2 :(得分:0)
您可能需要做的是将可执行命令用双引号引起来:
@Echo Off
For /F Delims^=^ EOL^= %%A In ('""C:\Program Files\BOGUS_PATH\FAKE.exe""'
)Do Echo(%%A
Pause
其中双引号的内部集合用于保护路径中的已知空间,而在将内容传递给cmd.exe
实例时,外部集合用于保护内部的双引号,其中括号命令是
然后,为了防止命令出现任何错误消息,您应该将STDERR
的输出重定向到NUL
:
@Echo Off
For /F Delims^=^ EOL^= %%A In ('""C:\Program Files\BOGUS_PATH\FAKE.exe" 2>Nul"'
)Do Echo(%%A
Pause
如果该可执行文件不存在,这将阻止错误消息The system cannot find the path specified.
,而Do
命令将不运行,(因为没有STDOUT
要处理) 。