Pure Windows batch is not very good at text processing.
I would use my JREPL.BAT regular expression text processing utility for this task. It is pure script (hybrid JScript/batch) that runs natively on any Windows machine from XP onward. Full documentation is available by executing jrepl /?
from the command line.
Here is a solution using JREPL.BAT. Note that the search is a regular expression, so you will have to escape search characters in VALUE TO SEARCH that are regex meta characters. The command reads "test.txt" and writes the result to "out.txt"
jrepl "([^\r\n]+\r?\n)*.*VALUE TO SEARCH.*\n?([^\r\n]+\r?\n?)*" "$0" /jmatch /m /f test.txt /o out.txt
You must use CALL JREPL
if you put the command within a batch script.
It is possible to solve this using pure batch, but it is complicated and much less efficient (much slower). Here is one solution.
@echo off
setlocal enableDelayedExpansion
set "infile=test.txt"
set "outfile=out.txt"
set "find=VALUE TO SEARCH"
set "emptyFile=empty.txt"
:: Compute end of file as number of lines + 1
for /f %%N in ('find /c /v "" ^<"%infile%"') do set /a last=%%N+1
:: Get list of line numbers of empty lines and append end of file
>"%emptyFile%" (
for /f "delims=:" %%N in ('findstr /n "^$" "%infile%"') do echo %%N
echo !last!
)
<"%infile%" >"%outFile%" (
set /a last=1
%= iterate list of found line numbers, ignoring lines that have already been printed =%
for /f "delims=:" %%A in ('findstr /nc:"!find!" "!infile!"') do if %%A geq !last! (
%= Locate beginning and end of found section, and compute lines to skip =%
set /a beg=0
set "end="
for /f "usebackq" %%B in ("%emptyFile%") do if not defined end (
if %%B gtr %%A (set /a end=%%B, start=beg+1, stop=end-1) else set beg=%%B
)
%= Skip lines until beginning of found section =%
for /l %%N in (!last! 1 !beg!) do set /p "ln="
%= Write empty line delimiter if not first found section =%
if !last! gtr 1 (echo()
%= Read and write found section =%
for /l %%N in (!start! 1 !stop!) do (
set /p "ln="
(echo(!ln!)
)
set /a last=end
)
)
del "%emptyFile%"
The pure batch solution above has the following limitations:
- Lines must be <= 1021 bytes long
- Control characters will be stripped from the end of each line
- Each line must be terminated by
\r\n
(Windows style). It will not work with \n
(Unix style).