Batch file 为什么文件的存在会影响在批处理脚本中解析其文件路径的方式?

Batch file 为什么文件的存在会影响在批处理脚本中解析其文件路径的方式?,batch-file,Batch File,当与/f和命令一起使用时,批处理for命令的工作方式有一些我不理解的地方 我试图循环一个可执行文件的输出。可执行文件不存在,这很好 但是,脚本并没有得到关于错误路径的预期错误,而是自发地错误地标记了字符串。这让我陷入了一个兔子洞,认为我已经格式化了for循环和/或使用了引号或反勾号错误 将可执行文件放置在该位置修复了该问题,使其看起来像路径字符串标记化取决于该路径上是否存在实际文件 为什么下面的批处理文件 @echo off for /f "usebackq delims=" %%i in (

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

我试图循环一个可执行文件的输出。可执行文件不存在,这很好

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

将可执行文件放置在该位置修复了该问题,使其看起来像路径字符串标记化取决于该路径上是否存在实际文件

为什么下面的批处理文件

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

输出
'C:\Program'未被识别为内部或外部命令、可操作程序或批处理文件。
而不是
系统无法找到指定的路径。

您可能需要做的是将可执行命令用双引号括起来:

@Echo关闭
对于(“'C:\Program Files\BOGUS\u PATH\FAKE.exe”“中的/F Delims^=^EOL^=%%A”
)Do回声(%%A
暂停
其中,内部双引号集用于保护路径中的已知空间,外部双引号集用于在将内容传递到运行括号内命令的
cmd.exe
实例时保护内部双引号集

然后,为了防止来自命令的任何错误消息,您应该将
STDERR
输出重定向到
NUL

@Echo关闭
对于(““C:\Program Files\BOGUS\u PATH\FAKE.exe”2>Nul”中的/F Delims^=^EOL^=%%A
)Do回声(%%A
暂停

如果可执行文件不存在,这将禁止显示错误消息,
系统无法找到指定的路径。
并且
Do
命令将不会运行(因为没有要处理的
STDOUT
).

FOR是Windows命令处理器
cmd.exe
的内部命令。使用带有选项
/F
FOR命令和执行命令会导致从
%ComSpec%/c
开始,并将指定的命令行作为进一步的参数还有一个命令进程在后台运行

要处理STDOUT的所有输出都由当前命令进程通过命令FOR执行批处理文件捕获,并在终止额外启动的
cmd.exe
后由FOR逐行处理

另外启动的命令进程的要处理的输出被重定向到当前命令进程的句柄STDERR,从而在STDERR既不在另外启动的命令进程中,也不在当前命令进程中的情况下,将其显示在控制台窗口中不同的句柄、文件或设备NUL

这可以在使用免费的Sysinternals(Microsoft)工具时看到

  • 下载包含进程监视器的ZIP文件
  • 将ZIP文件解压缩到任何本地目录中
  • 使用运行Process Monitor所需的“以管理员身份运行”启动
    Procmon.exe
  • 在首先显示的过程监控过滤器对话框中添加条目过程名称为cmd.exe,然后用按钮确定关闭对话框
  • 关闭工具栏上的最后五个选项,工具提示“显示文件系统”活动的“填充文件柜”符号除外
  • 按Ctrl+X以清除列表
  • 运行批处理文件
  • 切换回Process Monitor并按Ctrl+E停止捕获
  • 确保在列进程名称中看到列PID。右键单击列表标题,左键单击上下文菜单项选择列…如果尚未显示PID列,请选中进程ID,然后用确定关闭对话框窗口。我建议使用列标题PID的拖放操作将列PID向右移动到列进程名称
向上滚动以开始捕获的文件系统活动列表,并查找显示进程标识符不同于第一个进程标识符的
cmd.exe
的行。具有不同PID的第二个
cmd.exe
是由for启动的Windows命令处理器实例

右键单击第二个
cmd.exe
,在属性的上下文菜单中左键单击,选择选项卡处理,然后查看命令行,显示:

C:\Windows\system32\cmd.exe /c "C:\Program Files\BOGUS_PATH\FAKE.exe"
好的。现在我们知道了FOR分别
cmd.exe
在运行命令以捕获该命令的输出时所做的操作。关闭属性窗口

查看列表,可以看到第二个
cmd.exe
访问了哪些文件系统,以查找指定和现有目录中不存在的指定可执行文件。它接下来搜索
C:\Program Files\BOGUS\u PATH\FAKE.exe.*
也没有这样的文件作为结果

第一个参数字符串现在在参数分隔符上被拆分,在逗号或等号等其他字符中,它属于空格字符。因此,第一个参数字符串
C:\Program Files\BOGUS\u PATH\FAKE.exe
再次被参数分隔,导致
C:\Program
现在被解释为第一个参数字符串

cmd.exe
检查当前的目录路径是否存在
C:\
,这与以前的目录路径
C:\Program Files\BOGUS\u path
相同

接下来检查是否有与模式
C:\Program.*
匹配的文件,该模式不返回此类文件。然后
cmd.exe
检查是否有
"C:\Programs\MyApplication.exe C:\Temp\FileToProcess.txt"
"C:\Programs\MyApplication.exe" "C:\Temp\FileToProcess.txt"
@echo off
for /f "delims=" %%i in ('"C:\Program Files\BOGUS_PATH\FAKE.exe"') do (
    rem
)
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...
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.
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.
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:\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.
C:\WINDOWS\system32\cmd.exe /c "C:\Program Files\BOGUS_PATH\FAKE.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.
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 "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 "delims=" %%A in ('^""c:\some path\file.exe" "this&that" arg2^"') do ...