繁体   English   中英

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

[英]In Windows Batch, why a for loop surrounded by parenthesis won't expand a variable it's told to echo?

在我的项目中,我需要使用findstr从命令解析多行 output 。 为此,我按照这个答案创建了一个行数组并使用for循环逐一echo它们:

(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]%等等。

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

是什么导致了这个问题?

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


编辑:根据jeb 的回答,我添加了一个更长的片段,以及我认为问题在于findstr是一个外部 exe 的理解。

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的 output ,一个已放入数组( !info1!!info2等)的多行文本,使用findstr检测两个所需匹配项之一,然后使用find到 output 的数量匹配,这将决定下一行中的行为。

我试图通过所有这些实现的是避免多次启动 mkvmerge,但是我已经有了一个可行的替代方案,它只是再次调用 mkvmerge 而不是for /l循环(这意味着双管道在另一种情况下工作) .

感谢jeb我找到了这个答案,建议在findstr周围添加括号可以解决问题。 对我来说不是这样。

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

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

下一个问题是百分比表达式的嵌套不能以这种方式完成。 %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 进程,然后再次禁用延迟扩展。 为什么在管道代码块中延迟扩展会失败?

您可以将 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 和 pipe。

在您提供其他信息后:

括号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]%%

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM