从文本文件中提取找到的行+后续行

时间:2012-01-20 13:34:44

标签: windows batch-file cmd

我正在尝试编写一个批处理文件,该文件扫描多个文件并查找字符串“WARNING”。 到目前为止,我有:

FORFILES -m*.f08 -C"CMD /C FINDSTR /N "WARNING"  ECHO @FILE >> ListOfWARNINGS

问题一:它不会在新行中打印每个找到的字符串。

问题二:如何更改代码并添加IF语句,以便它还会在找到WARNING的行之后打印该行。

3 个答案:

答案 0 :(得分:2)

我认为,为了获得下一行,你实际上必须循环文件&据我所知,内容既不是forfiles也不是支持;

@echo off
setlocal enabledelayedexpansion
for %%f in (*.txt) do (
    echo Search %%f
    for /f "usebackq eol= delims=] tokens=1*" %%l in (`find /n /v "" "%%f"`) do (
        set line=%%m
        if !printnext!==1 (
            echo.%%m >> ListOfWARNINGS
            set printnext=0
        ) else (
            if not [!line!]==[] if not !line!==!line:WARNING=X! (
                echo %%m >> ListOfWARNINGS
                set printnext=1
            ) else (
                set printnext=0
            )
        )
    )
)

此处if not !line!==!line:WARNING=X!通过询问WARNING被替换为X后行是否等于自身来检测匹配。

C:\null>type a.txt

line 1
M O D E L S U M M A R Y
WARNING XXXXXXX
Line after warning
NUMBER OF CBAR ELEMENTS = 18655
lorem ipsum lorem ipsum lorem ipsum
WARNING ZZZZZZZ


C:\null>x.bat
Search a.txt

C:\null>type ListOfWARNINGS
WARNING XXXXXXX
Line after warning
WARNING ZZZZZZZ

C:\null>

答案 1 :(得分:1)

试试这个,

@ECHO OFF
:TOP
  IF (%1)==() GOTO END
  ECHO Value is "%1" and still running...
 SHIFT
 GOTO TOP
:END

请参阅此link

答案 2 :(得分:1)

Alex K解决方案效果很好,只要文件相对较小,它就能很好地运行。但是如果文件变大,性能就会成为一个主要问题。

我设置了一个包含4个文件的测试 - 3个小于1Kbyte的小文件,以及1个大~100byte文件。警告分散在文件中,包括大文件的开头和结尾附近。

Alex K解决方案 4.75分钟完成!问题是FOR IN()中的FINDSTR的整个结果集必须被缓存,而Windows对大数据集的效率非常低。

此外,该解决方案存在一个潜在的问题,即由于延迟扩展,它将损坏包含!的任何文件名和/或数据行。这可以通过适当地切换延迟扩展来解决,也可以根据需要在ENDLOCAL边界保留变量值。


将结果写入临时文件然后使用FOR / F读取临时文件要快得多。我修改了代码以使用临时文件(未显示),时间缩短为 43秒。


但仍有更快的解决方案。与FINDSTR的速度相比,FOR循环在读取文件时非常慢。下面是一个解决方案,它使用FINDSTR为每个警告搜索每个文件一次,再加上2次。这似乎是很多额外的工作,但完成我的测试用例的时间减少到 1秒

此解决方案还消除了文件名或文件内容中!引起的任何问题。

该解决方案针对WARNING数量与文件中的行数相比相对较小的情况进行了优化。如果WARNING的数量开始接近文件中的行数,那么它实际上会比上述中间解决方案慢。

此解决方案还在每个警告前面加上文件名和行号。

@echo off
setlocal disableDelayedExpansion
set searchFiles="*.f08"
set outFile="ListOfWARNINGS"
set tempFile="%temp%\warnings%random%.txt"
set tempFile2="%temp%\warnings2_%random%.txt"
(
  for /f "tokens=1,2 delims=:" %%A in ('findstr /m WARNING %searchFiles% nul') do (
    findstr /n "^" "%%A" nul >%tempFile%
    echo(>>%tempFile%
    set "file=%%A"
    set "next=0"
    setlocal enableDelayedExpansion
    findstr /n WARNING "!file!" >%tempFile2%
    for /f "usebackq delims=:" %%N in (%tempFile2%) do (
      if %%N==!next! (set "current=") else set current=/c:"!file!:%%N:"
      set /a "next=%%N+1"
      findstr /bi !current! /c:"!file!:!next!:" %tempFile%
    )
    endlocal
  )
)>%outFile%
del %tempFile% 2>nul
del %tempFile2% 2>nul

最后一个FINDSTR中的/I选项在逻辑上不应该是必需的。它可以防止FINDSTR有时会出现多个不同长度的文字搜索字符串的问题。