在 Windows Batch 中,为什么用括号括起来的 for 循环不会扩展它被告知要回显的变量?

问题描述

在我的项目中,我需要使用 findstr 解析命令的多行输出。为此,我按照 this answer 创建了一个行数组,并使用 echo 循环逐个 for

(for /L %n in (1 1 %info_count%) do echo %info[%n]%)| findstr /R /C:"[0-9s]: [0-9]" /C:"bytes"

问题是这会导致 echo 部分输出 %info[1]%%info[2]% 等等。

然而,删除第一组括号会导致 do 循环的 for 部分同时解释 echo 和管道部分,这意味着而不是六个 {{ 1}} 通过一个管道输出,我通过六个不同的管道获得六个(扩展的)echo 输出。

是什么导致了这个问题?

PS:上面的代码片段正是我在整个脚本运行后在结果提示中调查的内容。在主项目中,我很自然地对我的变量使用延迟扩展,并在批处理文件的循环内使用适当的变量(即 echosetlocal enabledelayedexpansion!var!


编辑:鉴于 jeb's answer,我添加了一个更长的片段,并且我理解问题在于 %%a 是一个外部 exe。

findstr

它的目的是分析 for /f %%d in ('^(for /L %%n in ^(1 1 !info_count!^) do echo !info[%%n]!^)^| ^(findstr /R /C:"[0-9s]: [0-9]" /C:"bytes"^)^| find /c /v ""') do ( if [%%d]==[0] ( ... ) else ( ... 的输出,这是一个多行文本,已放入数组(mkvmerge -i!info1! 等)中,使用 !info2 来检测两个所需匹配之一,然后使用 findstr 输出匹配数量,这将决定下一行中的行为。

我试图通过所有这些来实现的是避免多次启动 mkvmerge,但我已经有了一个可行的替代方案,它只是再次调用 mkvmerge 而不是 find 循环(这意味着双管道是在另一个场景中工作)。

This answer,我发现感谢 jeb,建议在 for /l 周围添加括号可以解决问题。对我来说不是这样。

解决方法

在命令行上测试这个没有用,因为行为与批处理文件不同。

这里的主要问题是百分比扩张。它在解析块时展开!

下一个问题是百分比表达式的嵌套无法通过这种方式完成。 %info[%n]% 被拆分为 %info[%n]%

在批处理文件中,您将使用延迟扩展来避免所有这些问题。

(for /L %%n in (1 1 !info_count!) do echo !info[%%n]!) | findstr /R /C:"[0-9s]: [0-9]" /C:"bytes"

但它仍然失败,因为您将延迟扩展的块通过管道传输到 findstr。 管道使用默认配置启动两个子 cmd.exe 进程,然后再次禁用延迟扩展。 Why does delayed expansion fail when inside a piped block of code?

您可以将 findstr 移动到块中,然后 !info[%%n]! 将在传输到新的 cmd.exe 实例之前展开。

for /L %%n in (1 1 !info_count!) do (
  echo !info[%%n]! | findstr /R /C:"[0-9s]: [0-9]" /C:"bytes"
)

这会更慢,因为它会为每个循环启动 findstr 和管道。

在您提供附加信息之后:

括号 findstr 在这里没有帮助,因为那不是您的问题。
如果您直接或在 cmd.exe 实例中启动 findstr 不会改变行为,那么只有在管道 findstr 部分存在百分比扩展时才需要该技巧。

如果您只想计算匹配项,则无需 find 即可完成。

set /a match_cnt=0
for /L %%n in (1 1 %info_count%) do (
  echo !info[%%n]! | findstr /R /C:"[0-9s]: [0-9]" /C:"bytes" > nul
  if !errorlevel! == 0 set /a match_cnt+=1
)

echo matches: !match_cnt!

您还可以修改初始代码以使用:

( 
    for /L %%n in (1 1 %info_count%) do @(
        cmd /V:on /C echo !info[%%n]!
    )
) | findstr /R /C:"[0-9s]: [0-9]" /C:"bytes"

或者没有(缓慢)调用 cmd /v:on

    call echo %%^^info[%%n]%%

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...