Bucko wrote: ↑09 Jun 2018 08:00
Please note that my question is limited to
findstr, because such a solution could be used for binary files too (which are my real target).
That is not necessarily true. As far as I'm concerned,
findstr on it's own, does not have the capability to filter specific line numbers. So the assumption that any solution of your task involving findstr, can automatically handle binary files is not true.
However there is a method which can handle binary files based on the criteria you have specified. There is also a method which can only be used to handle text files (Or more precisely files without <NULL> bytes) but in a much more efficient way.
findstr solution to handle text files:
Code: Select all
@echo off
setlocal EnableExtensions DisableDelayedExpansion
:: Parameters
set "Input=input.txt"
set "Output=output.txt"
:: The minimum value for startLine is 1
set /a "startLine=5, endLine=9"
set /a "startLine-=1"
if %startLine% EQU 0 (set "skip=") else set "skip=skip=%startLine%"
(for /F "%skip% tokens=1* delims=:" %%K in ('findstr /N /R "^" "%Input%"') do (
if %%K LEQ %endLine% (echo(%%L)
))>"%Output%"
The above will work well if the difference between endLine and total number lines in input files is relatively small. for example when endLine=130 and totalLines=134
But as difference gets bigger (endLine=130, totalLines=800) the performance will degrade because batch script have no means of immediate break from FOR loops once the job is done there is no need remain in the loop anymore. The only command that can immediately break FOR loops is
`exit` but that will also terminates the host cmd instance. The solution is to execute the FOR loop in a child instance of cmd along with exit command.
So the FOR loop block can replaced with this:
Code: Select all
>"%Output%" cmd /e:on /v:off /d /c for /F "%skip% tokens=1* delims=:" %%K in ^('findstr /N /R "^" "%Input%"'^) do @if %%K LEQ %endLine% ^(echo(%%L^) else exit
This can also be performance killer if the difference between endLine/totalLine is too small and you are processing too many files in this condition. So I think ShadowThief's solution may better suite your needs in this regards. You should test and compare.
findstr solution to handle binary files:
Code: Select all
@echo off
setlocal EnableExtensions DisableDelayedExpansion
:: Parameters
set "Input=input.bin"
set "Output=output.bin"
set /a "startLine=5, endLine=9"
set /a "cureLine=startLine-1, Lines=endLine-startLine+1, MaxDigits=9"
(for /L %%. in (1,1,%Lines%) do (
set /a "cureLine+=1, Num=cureLine, LeadChars=1"
for /L %%. in (1,1,%MaxDigits%) do set /a "LeadChars+=!!Num, Num/=10"
findstr /N /R "^" "%Input%"|(findstr /R "^%%cureLine%%:")|((for /L %%. in (1,1,%%LeadChars%%) do @pause)>nul & findstr /R "^")
REM // This line takes into account the possibility for disabled command extensions. Use instead of above if that is a concern.
REM findstr /N /R "^" "%Input%"|(findstr /R "^%%cureLine%%:")|cmd /e:on /d /c ^(for /L %%^^^. in ^(1,1,%%LeadChars%%^) do @pause^)^>nul ^& findstr /R "^"
))>"%Output%"
This is based on this assumption:
Bucko wrote: ↑09 Jun 2018 12:22
All my binary files (which I intend to use) have "lines" (i.e. newline characters), and these "lines" are not to long for findstr (there is a length limit). So findstr definitely would work with my binary data.
Be aware that this method is extremely slow and inefficient in terms of performance but should do the job. That was the best I could come up with.