2

I need to parse a text file. I want to find the firstline in the text file

: the first line to find
set firstLine=------------------------------------------------------------------------------------------------------------------

and find the last line

:: the last line to find
set lastLine=*******************************************************************************************************************

Then I need to export to a new file everything between those two line.

echo     >> M:\TESTING\Output.txt

I'm a beginner with this and I've searched for days, but am not finding how to do this.

I looked at for loops and if statements, but I'm still puzzled.

    for /f "tokens=1 delims= " %%f in (M:\TESTING\*.txt) do (

    :: sets then the line variable to the line just read
    set line=%%f
    :: the first line to find
    set firstLine=------------------------------------------------------------------------------------------------------------------ 
    :: the last line to find
    set lastLine=*******************************************************************************************************************

Then if %line% = %fistLine% start the export.....

Any direction will be appreciated. thanks.

Dennis van Gils
  • 3,487
  • 2
  • 14
  • 35
dj59
  • 21
  • 1

2 Answers2

4

@DennisvanGils' approach is a good start and will do well in many cases.
However, it will not produce an exact copy of the text file content between the given lines:

  • leading whitespaces (SPACE and TAB) will be removed (due to tokens=* option),
  • lines starting with ; will be skipped (due to the default option eol=; of for /F), and
  • empty lines will be skipped as well (as for /F always skips such).

To get an exact copy of the text file portion, you could use the following code snippet:

@echo off
set "INFILE=M:\TESTING\input.txt"
set "OUTFILE=M:\TESTING\output.txt"
set "FIRSTLINE=------------------------------------------------------------------------------------------------------------------"
set "LASTLINE=*******************************************************************************************************************"
setlocal EnableExtensions DisableDelayedExpansion
set "FLAG="
> "%OUTFILE%" (
    for /F "delims=" %%L in ('findstr /N "^" "%INFILE%"') do (
        set "LINE=%%L"
        setlocal EnableDelayedExpansion
        set "LINE=!LINE:*:=!"
        if "!LINE!"=="%FIRSTLINE%" (
            endlocal
            set "FLAG=TRUE"
        ) else if "!LINE!"=="%LASTLINE%" (
            endlocal
            goto :CONTINUE
        ) else if defined FLAG (
            echo(!LINE!
            endlocal
        ) else (
            endlocal
        )
    )
)
:CONTINUE
endlocal

Core function here is findstr, which is configured so that every line in the file is returned, prefixed with a line number and a colon :. Its output is then parsed by a for /F loop. Because of the prefix, no line appears to be empty and therefore every one is iterated by the loop. In the body of the loop, the prefix is removed by the set "LINE=!LINE:*:=!" command for each line.

The variable FLAG is used to decide whether or not the current line is to be output; if it is defined, that is, a value is assigned, the command echo !LINE! is executed; otherwise it is not. FLAG is set if the current line matches the string in %FIRSTLINE%; if the line matches the string in %LASTLINE%, a goto command is executed which breaks the loop. This means also that only the first block between %FIRSTLINE% and %LASTLINE% matches is output.

If there might occur multiple %FIRSTLINE% and %LASTLINE% matches within the text file and you want to output every block, replace the goto command line by set "FLAG=".

Note that this approach does not check whether %FIRSTLINE% occurs before %LASTLINE%, nor does it even check for existence of %LASTLINE% (all remaining lines to the end of file are output in case). If all this is important, the logic need to be improved and even a second loop will be required most likely.

Community
  • 1
  • 1
aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • The `> "%OUTFILE%"`, does that set the output stream to the outfile? I've never encountered that before. – Dennis van Gils Nov 11 '15 at 08:08
  • 1
    Yes, it does; you can use redirection even for a code block `()`; and the position of the redirection part can be at the beginning or at the end -- see also [this post](http://stackoverflow.com/a/25562437/5047996)... – aschipfl Nov 11 '15 at 08:16
  • This is excellent! Works Perfect. Now I have one more addition to figure out. I want the first 7 lines of the input file to output before it outputs the data between %FIRSTLINE% and %LASTLINE%. Thank You. – dj59 Nov 19 '15 at 15:22
  • PLEASE Disregard this last comment. I have it figured out. – dj59 Nov 19 '15 at 15:39
  • Okay... please consider to upvote answers that helped and to accept the answer that helped you most (which fully coveres your original problem)... – aschipfl Nov 19 '15 at 17:39
2

What you should do in this case is use a variable like a boolean to know if you encountered the startline and endline yet, and to know if you have to output the lines.

Also, you should use setlocal ENABLEDELAYEDEXPANSION with ! instead of % so you can change variables in loops and ifs (for more information about that, see this. The usage of () after if is not needed in this case, since the if is on one line, but they make things easier to read in my opinion. If you want to output the start and endline too, switch the checks for the start and endlines.

@echo off & setlocal ENABLEDELAYEDEXPANSION
set start=0
:: the first line to find
set firstLine=------------------------------------------------------------------------------------------------------------------
:: the last line to find
set lastLine=*******************************************************************************************************************
for /F "tokens=*" %%A in (TEST.txt) do (
:: sets then the line variable to the line just read
set line=%%A
if "!line!"=="!lastLine!" (set start=0)
if !start! equ 1 (echo !line!>>TESTOUTPUT.txt)
if "!line!"=="!firstLine!" (set start=1)
)

This should do what you want. Note that when you encounter a startline a second time it starts reading again.

Community
  • 1
  • 1
Dennis van Gils
  • 3,487
  • 2
  • 14
  • 35
  • Your approach may be sufficient for many applications (+1); however, there are some issues -- take a look at [my answer](http://stackoverflow.com/a/33641615/5047996)... – aschipfl Nov 10 '15 at 23:29