问题描述
在我的项目中,我需要使用 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:上面的代码片段正是我在整个脚本运行后在结果提示中调查的内容。在主项目中,我很自然地对我的变量使用延迟扩展,并在批处理文件的循环内使用适当的变量(即 echo
、setlocal 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]%%