Search code examples
windowsbatch-filecmdnested-loops

Batch - Get block of text between flags, output and iterate over all files


I've got a bunch of text files in a directory that have a block of text I want to extract between two strings into a new text file of a similar name. I've got the single file working but think I've come unstuck with looping through all .txt files. Maybe at the "goto" command? Here is the original, single file code I used: Batch File - Find two lines then copy everything between those lines

~Top Break
foobar
~ more data title
more foobar 
~Bottom Break
Garbage data

I have this code that works for a single file called FileNumber1.txt.

@echo off

    set "FIRSTLINE=~Top Break"
    set "LASTLINE=~Bottom Break"
    set "INFILE=FileNumber1.txt"
    setlocal EnableExtensions DisableDelayedExpansion
    set "FLAG="
    > "%INFILE%_MyData.txt" (
        rem findstr configured so that each line in a  file is given a "1:" number and colon.
        for /F "delims=" %%L in ('findstr /N "^" "%INFILE%"') do (
            set "LINE=%%L"
            setlocal EnableDelayedExpansion
        rem this LINE=!LINE:*:=! removes the any character before the Colon. *:
            set "LINE=!LINE:*:=!"
        rem this block of code checks to see if line of text = Firstline variable, if so FLAG = TRUE
            if "!LINE!"=="%FIRSTLINE%" (
                endlocal
                set "FLAG=TRUE"
        rem this block of code checks to see if line of text = Lastline variable, if so goto :Continue and end the loop
            ) else if "!LINE!"=="%LASTLINE%" (
                endlocal
                goto :CONTINUE
            ) else if defined FLAG (
                echo(#!LINE!
                endlocal
            ) else (
                endlocal
            )
        )
    )
    :CONTINUE
    endlocal
    
    
    
   

NewFile1_MyData.txt Output:

foobar
~ more data title
more foobar 

I've tried to wrap this in another "FOR" loop that looks for all txt files in the same directory. This is my code that isn't working.

@echo off

set "FIRSTLINE=~Top Break"
set "LASTLINE=~Bottom Break"

for /F %%f in (*.txt) do (
set "INFILE=%%f"
setlocal EnableExtensions DisableDelayedExpansion
set "FLAG="
> "%INFILE%_OldHeader.txt" (
    rem findstr configured so that each line in a  file is given a "1:" number and colon.
    for /F "delims=" %%L in ('findstr /N "^" "%INFILE%"') do (
        set "LINE=%%L"
        setlocal EnableDelayedExpansion
    rem this LINE=!LINE:*:=! removes the any character before the Colon. *:
        set "LINE=!LINE:*:=!"
    rem this block of code checks to see if line of text = Firstline variable, if so FLAG = TRUE
        if "!LINE!"=="%FIRSTLINE%" (
            endlocal
            set "FLAG=TRUE"
    rem this block of code checks to see if line of text = Lastline variable, if so goto :Continue and end the loop
        ) else if "!LINE!"=="%LASTLINE%" (
            endlocal
            goto :CONTINUE
        ) else if defined FLAG (
            echo(#!LINE!
            endlocal
        ) else (
            endlocal
        )
    )
)

endlocal


:CONTINUE
))

The Command window gets to the "for /F" statement and exits.


Solution

  • Mmm... I would change the method to extract the lines for a simpler one based on lines to skip at beginning of file and number of lines to extract. After that, I would use a for to process all files and call a subroutine to extract the lines:

    @echo off
    setlocal EnableDelayedExpansion
    
    set "FirstLine=~Top Break"
    set "LastLine=~Bottom Break"
    
    rem Process all text files in this folder
    for %%f in (*.txt) do (
    
       rem Search for First line and Number of lines
       set "FirstNum="
       for /F "delims=:" %%n in ('findstr /C:"%FirstLine%" /C:"%LastLine%" /N "%%f"') do (
          if not defined FirstNum (
             set "FirstNum=%%n"
          ) else (
             set /A "LastNum=%%n-FirstNum-1"
          )
       )
    
       rem Copy the lines
       call :CopyLines >"%%~Nf_MyData.out" "%%f", !FirstNum!, !LastNum!  
    
    )
    ren *.out *.txt
    goto :EOF
    
    
    :CopyLines File, Skip, Num
    set "Num=%3"
    for /F "usebackq skip=%2 delims=" %%a in (%1) do (
       setlocal DisableDelayedExpansion
       echo %%a
       endlocal
       set /A Num-=1
       if !Num! equ 0 exit /B
    )
    exit /B