【问题标题】:Batch file to extract text from file从文件中提取文本的批处理文件
【发布时间】:2019-09-25 04:59:44
【问题描述】:

我有一个试图从中提取特定行的日志文件。当我将文件裁剪为上下几行时,我能够得到它。但是,我试图找到多个阻止使用 FULL 文件的实例。

以下是我尝试过的一些代码...

 for /f "tokens=1* delims=[]" %%a in ('find /n "    <Line Text="***********TEST1  TEST  TEST************" />" ^< TEST.LOG') do (set H=%%a
 )

 for /f "tokens=1* delims=[]" %%a in ('find /n "</Report>" ^< TEST.LOG') do (
 set T=%%a
 )

 for /f "tokens=1* delims=[]" %%a in ('find /n /v "" ^< TEST.LOG') do (
 if %%a GEQ !H! if %%a LEQ !T! echo.%%b
 )>> newfile.txt

我希望得到以下结果:

 <Line Text="***********TEST1  TEST  TEST************" />
 ~ALL LINES IN BETWEEN~
 </Report>

【问题讨论】:

    标签: batch-file cmd find findstr


    【解决方案1】:

    更新:

    您想找到&lt;Line Text="***********TEST1 TEST TEST************" /&gt;,然后打印它和任何一行,直到遇到第一个&lt;/Report&gt;,然后查找下一个&lt;Line Text="***********TEST1 TEST TEST************" /&gt; 并打印它和接下来的每一行,直到下一个&lt;/Report&gt; 每次它贯穿始终?

    – Ben Personick 1 小时前

    或者你只是想从第一个&lt;Line Text="***********TEST1 TEST TEST************" /&gt; 到第一个&lt;/Report&gt;

    – Ben Personick 1 小时前

    找到&lt;Line Text="***********TEST1 TEST TEST************" /&gt;,然后打印它和任何一行,直到遇到第一个&lt;/Report&gt;,然后查找下一个&lt;Line Text="***********TEST1 TEST TEST************" /&gt;,并在每次出现时打印它和接下来的每一行,直到下一个&lt;/Report&gt;。我觉得应该只有 1 个序列,但是,有时这种情况很可能发生。谢谢你的提问,非常中肯的问题!

    – T-Diddy 1 小时前

    好的,这应该会按照您的预期工作,但是,如果有很多意外字符,修改行的输出方式可能更有意义改为使用SET回声。

    @(setlocal
      ECHO OFF
      SET "_LogFile=C:\Admin\TestLog.log"
      SET "_ResultFile=C:\Admin\TestLog.txt"
      SET "_MatchString_Begin=<Line Text="***********AAAAA BBBB CCCC************" />"
      SET "_MatchString_End=</Report>"
      SET "_Line#_Begin="
    )
    
    CALL :Main
    
    ( ENDLOCAL
      EXIT/B
    )
    :Main
      IF EXIST "%_ResultFile%" (
        DEL /F /Q "%_ResultFile%"
      )
      ECHO.&ECHO.== Processing ==&ECHO.
      FOR /F "Delims=[]" %%# IN ('
        Find /N "%_MatchString_Begin:"=""%" "%_LogFile%" ^| FIND "["
      ') DO (
        ECHO. Found Match On Line %%#
        SET /A "_Line#_Begin=%%#-1"
        CALL :Output
      )
      ECHO.&ECHO.== Completed ==&ECHO.&ECHO.Results to Screen will Start in 5 Seconds:
      timeout 5
      Type "%_ResultFile%"
    GOTO :EOF
    
    :Output
      FOR /F "SKIP=%_Line#_Begin% Tokens=* usebackq" %%_ IN (
        "%_LogFile%"
      ) DO (
        ECHO(%%_
        ECHO("%%_" | FIND /I "%_MatchString_End%" >NUL&&(
          GOTO :EOF
        )
      )>>"%_ResultFile%"
    GOTO :EOF
    

    原始响应仅显示第一个匹配的内容,基于此评论:

    这对我的“裁剪”文件非常有用。然而,在原版中,我唯一拥有的唯一行是&lt;Line Text="***********AAAAA BBBB CCCC************" /&gt;。我似乎无法使用整行,因为我的批次刚刚退出,但能够输入“***********AAAAA BBBB CCCC************”并且不会踢出我的批次,但是,存在于其他地方。因此,需要其他参数,因为它在文件中是唯一的。我想要下一个:按顺序。否则,这个“&lt;/Report&gt;”存在于上面的另一个部分中,我不想要并相信会导致问题。 – T-Diddy 3 分钟前

    好吧,我是这么想的。

    试试这个:

    @(setlocal
      ECHO OFF
      SET "_LogFile=C:\Admin\TestLog.log"
      SET "_MatchString_Begin=<Line Text="***********AAAAA BBBB CCCC************" />"
      SET "_MatchString_End=</Report>"
      SET "_Line#_Begin="
      SET "_Line#_End="
    )
    REM SET
    FOR /F "Delims=[]" %%# IN ('
      Find /N "%_MatchString_Begin:"=""%" "%_LogFile%" ^| FIND "["
    ') DO (
      IF NOT DEFINED _Line#_Begin (
        SET /A "_Line#_Begin=%%#-1"
        ECHO.SET /A "_Line#_Begin=%%#-1"
      )
    )
    FOR /F "SKIP=%_Line#_Begin% Tokens=* usebackq" %%_ IN (
      "%_LogFile%"
    ) DO (
      IF NOT DEFINED _Line#_End (
        ECHO(%%_
        ECHO("%%_" | FIND /I "%_MatchString_End%" &&(
          SET "_Line#_End=1"
        )
      )
    )
    PAUSE
    

    【讨论】:

    • 好的!我相信这可能适用于我在弹出 CMD 窗口时看到的启动画面。我只需要将它输出到 TXT 文件,并认为这就是我要寻找的东西!
    • 与其双击一个 cmd 脚本,不如打开一个 cmd 提示符然后从内部运行脚本,这样 cmd 提示符就会一直存在并让您看到结果。与此同时,我会暂停一下。此外,如果由于您的字段中的字符而出现错误,我可以发布一个我用来解决打印几乎任何字符的替代方法。但我可能还需要稍微修改代码以实际为每个第一个和之间的每一行执行此操作last found 而不是仅仅使用提供的更简单的方法。 LMK
    • 这正是我想要的。现在,如果我们可以输出到 TXT 文件,那就完美了!
    • @T-Diddy 很高兴为您提供帮助! :) 至于输出到文本文件,将其全部输出到 txt 文件的最简单方法是在我提到的 CMD 提示符下运行它,然后在末尾添加 &gt;&gt;"C:\Path\To\File.txt"。因此,假设您将其保存为 LogExtract.cmd 在文件夹 C:\Scripts 中,然后您将执行 Start --&gt; RUN --&gt; CMD 然后在 CMD 提示符中输入:C:\Scripts\LogExtrat.cmd &gt;&gt;"C:\Path\To\File.txt"
    • @T-Diddy 现在是第二个最容易完成的事情,我将其修改为直接写入新文件(只需要两行),但随后我当然开始让它报告更多它也在做什么,所以我现在发布修改后的版本来代替现有版本
    【解决方案2】:

    为执行命令和可执行文件而非文本文件处理而设计的 Windows 命令处理器绝对是过滤TEST.LOG 的最差选择。由于原因,请完整阅读我在How to read and print contents of text file line by line? 上的回答。此处详细描述的批处理文件代码用作以下批处理文件代码的模板:

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    if not exist "Test.log" goto EndBatch
    set "OutputLines="
    
    (for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /N "^" "Test.log"') do (
        set "Line=%%I"
        setlocal EnableDelayedExpansion
        if defined OutputLines (
            echo(!Line:*:=!
            if not "!Line:</Report>=!" == "!Line!" (
                endlocal & set "OutputLines="
            ) else endlocal
        ) else if not "!Line:<Line Text=!" == "!Line!" (
            echo(!Line:*:=!
            endlocal & set "OutputLines=1"
        ) else endlocal
    ))>"newfile.txt"
    
    if exist "newfile.txt" for %%I in ("newfile.txt") do if %%~zI == 0 del "newfile.txt"
    
    :EndBatch
    endlocal
    

    此批处理文件将从包含不区分大小写的字符串 &lt;Line Text 的行到包含不区分大小写的字符串 &lt;/Report&gt; 的行或来自 Test.log 的文件末尾的所有行写入文件 newfile.txt

    注意:!Line:= 之间的搜索字符串不能包含等号,因为等号被 Windows 命令处理器解释为搜索字符串之间的分隔符,此处为 &lt;/Report&gt;&lt;Line Text 和替换字符串,这里有两次空字符串。 Windows 命令处理器将搜索字符串开头的星号* 解释为替换从行首到第一次出现的字符串替换的所有内容,而不是在行中查找的字符。但这对于这个用例来说并不重要。

    如果标记要提取的块的开头和结尾的两行是固定的并且不包含任何可变部分,则可以在不进行字符串替换的情况下进行两个字符串比较,从而可以比较包含等号的字符串。

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    if not exist "Test.log" goto EndBatch
    
    set "BlockBegin= <Line Text="***********TEST1  TEST  TEST************" />"
    set "BlockEnd= </Report>"
    set "OutputLines="
    
    (for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /N "^" "Test.log"') do (
        set "Line=%%I"
        setlocal EnableDelayedExpansion
        if defined OutputLines (
            echo(!Line:*:=!
            if "!Line:*:=!" == "!BlockEnd!" (
                endlocal & set "OutputLines="
            ) else endlocal
        ) else if "!Line:*:=!" == "!BlockBegin!" (
            echo(!Line:*:=!
            endlocal & set "OutputLines=1"
        ) else endlocal
    ))>"newfile.txt"
    
    if exist "newfile.txt" for %%I in ("newfile.txt") do if %%~zI == 0 del "newfile.txt"
    
    :EndBatch
    endlocal
    

    此变体将每一整行区分大小写与分配给环境变量BlockBeginBlockEnd 的字符串进行比较,以确定从哪一行开始以及在哪一行停止输出。

    要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

    • del /?
    • echo /?
    • endlocal /?
    • findstr /?
    • for /?
    • goto /?
    • if /?
    • set /?
    • setlocal /?

    另见:

    【讨论】:

      【解决方案3】:

      你可以试试这个代码:

      @echo off
      Title Extract Data between two tags
      Set "InputFile=InputFile.txt"
      Set From_Start="<Line"
      Set To_End="</Report>"
      Set "OutputFile=OutputFile.txt"
      Call :ExtractData %InputFile% %From_Start% %To_End%
      Call :ExtractData %InputFile% %From_Start% %To_End%>%OutputFile%
      If Exist %OutputFile% Start "" %OutputFile%
      Exit
      ::'*************************************************************
      :ExtractData <InputFile> <From_Start> <To_End>
      (
      echo Set fso = CreateObject^("Scripting.FileSystemObject"^)
      echo Set f=fso.opentextfile^("%~1",1^)
      echo Data = f.ReadAll
      echo Data = Extract(Data,"(%~2.*\r\n)([\w\W]*)(\r\n)(%~3)"^)
      echo WScript.StdOut.WriteLine Data
      echo '************************************************
      echo Function Extract(Data,Pattern^)
      echo    Dim oRE,oMatches,Match,Line
      echo    set oRE = New RegExp
      echo    oRE.IgnoreCase = True
      echo    oRE.Global = True
      echo    oRE.Pattern = Pattern
      echo    set Matches = oRE.Execute(Data^)
      echo    If Matches.Count ^> 0 Then Data = Matches^(0^).SubMatches^(1^)
      echo    Extract = Data
      echo End Function
      echo '************************************************
      )>"%tmp%\%~n0.vbs"
      cscript //nologo "%tmp%\%~n0.vbs"
      If Exist "%tmp%\%~n0.vbs" Del "%tmp%\%~n0.vbs"
      exit /b
      ::****************************************************
      

      【讨论】:

      • 不幸的是 "Set From_Start=" 我要从中提取的文件中的这些内容太多了。以下是我唯一拥有的唯一行:。然后我需要下一个 " " 依次落在这条独特的线之后。开始认为我可能会要求不可能的事情?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多