在 DOS 批处理文件中找到匹配项后如何打印所有控制台输出?

Posted

技术标签:

【中文标题】在 DOS 批处理文件中找到匹配项后如何打印所有控制台输出?【英文标题】:How to print all console output after a match is found in a DOS batch file? 【发布时间】:2015-10-25 21:36:23 【问题描述】:

使用 DOS 批处理语法,我需要等到模式出现在控制台输出中,然后打印之后的所有内容(或至少在匹配后打印 N 行)。我怎样才能做到这一点? (类似于 Unix 中的 grep +A )。我可以简单地这样做,以获得模式:

run_my_command | findstr "my_pattern"

但是查看 findstr 手册,似乎没有打印所有内容的开关(或模式后的 N 行)。我不是DOS批处理方面的专家,所以如果你有想法,请直接。

编辑:

这是我输出的最后一部分(即在这些行之前有很多行,但我感兴趣的是测试结果,即“结果:”之后的所有内容都是粗体)

...

...

21:23:26.332 [Thread-4] 调试 o.s.b.f.s.DisposableBeanAdapter - 在名为 'ehcache' 的 bean 上调用 destroy()

21:23:26.332 [Thread-4] 信息 o.s.c.e.EhCacheManagerFactoryBean - 关闭 EhC​​ache CacheManager

21:23:26.332 [Thread-4] 调试 net.sf.ehcache.CacheManager - CacheManager 已经关闭

结果:测试错误:ReceiptsSearchRequestBuilderTest.testCreateSearchRequest_loadDate:97 » IllegalArgument ReceiptLineControllerTest.testFind:26 » NullPointer 测试运行:229,失败:0,错误:2,跳过:0

[信息] ----------------------------------

[INFO] 构建失败

[信息] ----------------------------------

[INFO] 总时间:23.213 秒

[INFO] 完成于:2015-08-03T14:23:26-07:00

[INFO] 最终内存:19M/453M

[信息] -------------------------------

编辑:

这是我的脚本。当我不重定向到 %log% 时,它只会在我的模式之后打印文本,这正是我想要的。但是当我将它重定向到 %log% 时,日志文件包含所有文本(stderr 也正确地转储为 null)。

@echo OFF

SET MAVEN_PROFILE=ie
SET root_dir="%USERPROFILE%\Desktop\MyFolder"
SET log=%root_dir%/log.txt

powershell -c "$txt=(&mvn -P %MAVEN_PROFILE% -Dtest=LoginTest test > %log% 2> null) -join \"`r`n\"; $i=$txt.indexof('Results :'); if($i -ge 0)  $j=$txt.lastindexof(\"`n\",$i); write-host $txt.substring([math]::max(0,$j+1))"

【问题讨论】:

【参考方案1】:

这里的想法与 Aacini 的答案类似,但它使用了一个名为 JREPL.BAT 的已编写的混合 JScript/批处理实用程序,它为批处理提供了复杂的正则表达式文本处理功能。 JREPL.BAT 是纯脚本,可​​以在从 XP 开始的任何 Windows 机器上本地运行。完整的文档嵌入在脚本中。

跳过输出并从以Results : 开头的第一行开始打印

yourCommand | jrepl "^Results :[\s\S]*" "$0" /jmatch /m

仅打印以Results : 开头的行,以及接下来的 4 行(共 5 行)

yourCommand | jrepl "^Results :(.*\n)0,4.*$" "$0" /jmatch /m

以上两个命令都使用/M 多行选项,这意味着必须将整个输出加载到内存中。在命令完成之前不会打印任何内容。如果输出为数 GB,或者长时间运行,并且您希望尽快看到输出,这可能是个问题。

使用更多代码和用户提供的 JScript,可以独立处理和打印每一行 - 没有延迟,也没有大小限制:

打印第一行以Results :开头的所有内容

yourCommand | jrepl "^Results :.*|^.*" "go=true;$0|go?$0:false" /jmatch /t "|" /jbeg "var go=false"

只打印以Results : 开头的行,再加上接下来的 4 行(共 5 行)

yourCommand | jrepl "^Results :.*|^.*" "go=5;$0|(--go>0)?$0:false" /jmatch /t "|" /jbeg "var go=0"

【讨论】:

【参考方案2】:

这是一个使用 powershell 的单行程序,您可以从批处理文件中运行它,在 120MB 输出的末尾找到一个字符串需要 10 秒:

powershell -c "$txt=(&your_console_app -with -arguments) -join \"`r`n\"; $i=$txt.indexof('string_to_search_for'); if($i -ge 0)  $j=$txt.lastindexof(\"`n\",$i); $txt.substring([math]::max(0,$j+1)) "
相应地替换your_console_app -with -argumentsstring_to_search_for。如果那些包含双引号,则将它们转义为\"。 在新行中添加pause,以便在需要时保持控制台窗口打开。

使用实际命令行输出到标准输出并重定向到文件的示例:

@echo OFF

SET MAVEN_PROFILE=ie
SET root_dir="%USERPROFILE%\Desktop\MyFolder"
SET log=%root_dir%/log.txt

powershell -c "$txt=(&mvn -P %MAVEN_PROFILE% -Dtest=LoginTest test 2>nul) -join \"`r`n\"; $i=$txt.indexof('Results :'); if($i -ge 0)  $j=$txt.lastindexof(\"`n\",$i); $txt.substring([math]::max(0,$j+1)) " >results.txt

或者,您可以直接从 powershell 代码中写入文件:

powershell -c "$txt=(&mvn -P %MAVEN_PROFILE% -Dtest=LoginTest test 2>nul) -join \"`r`n\"; $i=$txt.indexof('Results :'); if($i -ge 0)  $j=$txt.lastindexof(\"`n\",$i); $txt.substring([math]::max(0,$j+1)) | out-file 'results.txt' "

【讨论】:

太棒了。这在何时有效,并且仅将我想要的内容打印到控制台。我怎样才能使重定向也起作用? (请在原始问题中查看我上面的代码)。我可以看到创建了日志文件,因此您的命令似乎可以解决 %log%,但问题是日志包含所有控制台输出(而不仅仅是模式之后的输出) 添加了一个实际示例。请注意,无需重定向到 %log%,因为 powershell 会读取命令的标准输出。当您重定向它时,命令将其完整输出发送到日志文件,然后 powershell 什么也没看到。 啊!说得通。该脚本现在可以成功运行。非常感谢! 好的,我现在看到了这个问题。当控制台输出很小时它确实有效(即当我只运行 1 个测试时它有效。控制台输出不是太多,所以它似乎工作正常)。但是当我为我们的整个测试套件(目前有 56 个测试)尝试它时,命令似乎永远不会完成,所以脚本永远不会终止:( 想法? 如果你运行整个测试套件并从命令行将输出重定向到一个文件会发生什么:mvn .......... >logfile.txt?【参考方案3】:

当然,您需要执行通过管道连接的两个部分,就像在您的示例中一样。虽然可以用纯Batch来编写右侧管道进程,但是批处理文件处理在从管道中读取时会出现同步问题,所以我们需要使用不同的语言。

JScript 是一种比 Batch 更强大的编程语言,它在从 XP 开始的所有 Windows 版本中都可用,并且很容易将 Batch 和 JScript 代码组合在同一个混合脚本中:

编辑:第一行缺少@。固定

@set @Batch=1 /*
@echo off
run_my_command | CScript //nologo //E:JScript "%~F0"
goto :EOF    */

// JScript section

var lineFound = false, numOfLines = N;
while ( ! WScript.Stdin.AtEndOfStream ) 
   line = WScript.Stdin.ReadLine();
   if ( ! lineFound  &&  line.indexOf("my_pattern") >= 0 ) lineFound = true;
   if ( lineFound  &&  numOfLines ) 
      WScript.Stdout.WriteLine(line);
      --numOfLines;
   

将之前的代码保存在扩展名为 .bat 的文件中;您需要在代码中调整几个细节。

【讨论】:

请编辑您的问题并插入输出数据的 small 部分(10 或 15 行)和模式搜索,以便我可以进行自己的测试。请注意,“它不起作用”没有描述任何内容...完成更改后,请在此处发表评论作为建议。 用示例输出更新了我的帖子。 操作!第 1 行的“批次”名称前缺少 @@set @Batch=1 /*。请修复它并重试... :( Aacini,当我尝试它时,我得到了这个错误:Microsoft JScript compilation error: Expected ';' 从脚本的最后一行(在代码的末尾)。我试着放一个;在“%~F0”之后,然后我得到“myfile.bat cannot be found”错误。【参考方案4】:

你的意思是模式出现了?你想在哪里找到?由于您要打印 N 行或之后的所有内容,因此我假设您正在文本文件中搜索单词而不是模式。

@echo off
set /p word = What word/pattern you are searching for? ^>
set bool = 0

for /f "tokens=*" %%a in (Text.txt) do (
    if %%a == %word% set bool = 1
    if %bool% == 1 echo %%a
)

此脚本仅在找到您要查找的单词后打印所有内容。

【讨论】:

dark fang,我正在运行一个产生大量输出的命令。我想忽略大部分输出,基本上只打印在我的模式之后写的任何内容。 (最终将其重定向到另一个文件并保存)。所以我没有使用静态(固定大小)文本文件。如何使用您的脚本使其与实时命令输出一起工作? 只需将命令的输出重定向到一个临时文件:run_my_command >text.txt dark fang,我正在运行一个构建我们项目的 maven 命令。输出约为 120 MB(这是在我使用 --quiet 开关减少输出之后)。我用“mvn install”和“'mvn install'”替换了脚本的“Text.txt”部分,但它们似乎不起作用。有没有办法让它适用于我的情况? wOxxOm,是的,我最终会这样做,但首先我需要能够丢弃大部分输出,只捕获我感兴趣的输出。 我对maven不熟悉,但是cmd中可以调用“mvn install”吗?如果可以,请尝试将 cmd /c mvn install 替换为 Text.txt。由于批处理很慢,我认为不能很快完成 是的,可以。但它没有用。我看到的只是一个闪烁的 CMD 窗口(maven 命令至少需要几分钟才能完成,但是当我运行脚本时,我看到的只是一个 CMD 窗口的闪烁,然后什么也没有)。

以上是关于在 DOS 批处理文件中找到匹配项后如何打印所有控制台输出?的主要内容,如果未能解决你的问题,请参考以下文章

Linux三剑客(sed)-编辑匹配到的文本

Pandas 将文件名存储在列表中,并将所有文件读入数据框

Matlab中基本矩阵的不同结果

Java如何从文件中打印与给定模式匹配的所有字符串?

《Linux就该这么学》第十课

Shell输出文本中的指定行