Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

reading from a particular line on txt file

2,331 views
Skip to first unread message

Abhijat

unread,
May 22, 2012, 2:57:55 PM5/22/12
to
Hi All,
I can find out what I have to extract from a text file using
For /f "tokens=1 delims=:" %%a in ('findstr /n / c:"Old Identifier" %filename%') do set head=%%a set /a rowstart=head+2
Similarly, I can get rowend as well.
My question is - how can I extract all the rows between start and end and save the file

foxidrive

unread,
May 22, 2012, 7:40:04 PM5/22/12
to
sed -n %start%,%end%p file.txt >newfile.txt



--
Mic

Abhijat

unread,
May 22, 2012, 8:08:04 PM5/22/12
to
thanks Mic .. I m sure .. this will be spot on .. like always!
Meanwhile .. I was playing with the command tail ..

Todd Vargo

unread,
May 23, 2012, 12:01:38 AM5/23/12
to
This works in XP. Modify to suit your needs. All lines are indented with
2 or more spaces. Any lines beginning in 1st column have wrapped from
previous line.

@echo off
setlocal
set "filename=inputfile.txt"
set "outfile=outputfile.txt"

set "rowstart="
For /f "tokens=1 delims=:" %%a in (
'findstr /n /c:"Start Identifier" %filename%'
) do if not defined rowstart set /a rowstart=%%a+1
:: +1 added to end of line above to exclude start row

set "rowend="
For /f "tokens=1 delims=:" %%a in (
'findstr /n /c:"End Identifier" %filename%'
) do if not defined rowend set /a rowend=%%a-1
:: -1 added to end of line above to exclude end row

find "'% %vbs"<"%~f0">tmp.vbs
type "%filename%"|cscript /nologo tmp.vbs %rowstart% %rowend%
>"%outfile%"
del tmp.vbs
goto :eof
::Extract Mid lines vbs code
lines = Split(Wscript.StdIn.ReadAll,vbNewLine) 'vbs
For i = Wscript.Arguments(0)-1 To Wscript.Arguments(1)-1 'vbs
Wscript.StdOut.WriteLine lines(i) 'vbs
Next 'vbs
::end of batch

--
Todd Vargo
(Post questions to group only. Remove "z" to email personal messages)

Abhijat

unread,
May 23, 2012, 10:27:34 AM5/23/12
to
Hi Mic,
Sed does not work for me. I use XP professional.

foxidrive

unread,
May 24, 2012, 1:59:37 AM5/24/12
to
On 24/05/2012 00:27, Abhijat wrote:
> Hi Mic,
> Sed does not work for me. I use XP professional.

Did you download sed?

What was the error?


--
Mic

billious

unread,
May 24, 2012, 2:26:40 AM5/24/12
to
On 23/05/12 22:27, Abhijat wrote:
> Hi Mic,
> Sed does not work for me. I use XP professional.

SD is not supplied by Microsoft. Try Googling for it. It goes by the
byline "the stream editor". GNUSED would be a good start.

Here's a way to do it:

It has the obvious fault of stripping out leading "[" and "]"

@echo off
set start=3
set end=10
del outfile.txt 2>nul
for /f "tokens=1*delims=[]" %%i in (
' find /n /v "" ^<textfile.txt ' ) do (
if %%i geq %start% if %%i leq %end% (
set flag=%%j
if defined flag >>outfile.txt echo %%j
if not defined flag >>outfile.txt echo.
)
)

frank.w...@gmail.com

unread,
May 24, 2012, 10:22:39 AM5/24/12
to
From Abhijat :
>Sed does not work for me. I use XP professional.

There is no need for anything beyond CMD, and this is a
simple task. I'm on Android so this is not a working
script, but the solution involves something like this:

Set "start=text in first line"
Set "end=text in last line"
Set "flag="
for ... %%a in (...) do (
if [captured text] EQU "%start%" (
Set "flag=on"
) else if [captured text] EQU "%end%" (
Set "flag="
)
if DEFINED flag echo line >> file
)

Frank

Tom Lavedas

unread,
May 24, 2012, 3:44:22 PM5/24/12
to
The FOR strips out blank lines and the assumprion is that the text
captured by the variable (%%a) is distinct on a separate line, not
embedded in a line of text. In that case, a FIND or FINDSTR search is
called for rather than a simple EQU comparison.
_______________________
Tom Lavedas

frank.w...@gmail.com

unread,
May 25, 2012, 7:07:53 AM5/25/12
to
From Tom Lavedas :
>The FOR strips out blank lines ...

Yes, I've posted here a complete solution for that. Use
FINDSTR/N to get all lines, then with a calculated
offset remove the line number and colon. If you aren't
concerned about losing a leading colon then use it as a
delim ("delims=: tokens=1*") and take %%b. I think a
search for 'Frank findstr "calculate an offset"' might
find that particular message.

> ... and the assumprion is
>that the text
>captured by the variable (%%a) is distinct on a separate
>line, not
>embedded in a line of text.

That makes the comparison simpler.

>In that case, a FIND or
>FINDSTR search is
>called for rather than a simple EQU comparison.

But it isn't necessary.

Frank

Frank P. Westlake

unread,
May 28, 2012, 8:52:04 AM5/28/12
to
:: BEGIN SCRIPT
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: body.cmd
:: From the desk of Frank P. Westlake, 2012-05-27
:: 'body' meaning not necessarily 'head' nor 'tail'.
@Goto :main to avoid documentation.
BEGIN DOCUMENTATION
Searches for lines with the specified text
and prints all lines between.

USAGE
File input:
body [/N] [/S] [/X] [/1] start end filespec [filespec [filespec [...]]]
Redirected input:
body [/N] [/X] [/1] start [end] < FILE OR DEVICE
Piped input:
COMMAND | body [/N] [/X] [/1] start [end]

Options (not case sensitive):
/H Hide the start and end matching lines.
/N Print line numbers.
/S Check for the file[s] in subdirectories.
/X Match the line exactly. Otherwise the match is of any
case insignificant occurrance of the text.
/1 Find only the first group of matching lines.
start Text on the first line to be printed. Use "" to match a blank line.
end Text on the last line to be printed. Use "" to match a blank line.
Optional for pipes and redirection, in which case the remainder
of the file is printed.

- Follow switch with a hyphen to reverse the option.
For example, if the default is to print line numbers /N- will
disable line number printing.
- Wildcards are accepted for multiple files.
- The filename is printed to file stream 3, which may be
redirected to NUL:. For example:
body /s "" "-- " *.nws *.eml 3>NUL:
(prints message bodies until signature
cut-off)
END DOCUMENTATION
:main
@Echo OFF
SetLocal EnableExtensions
:: SET DEFAULTS
REM Set "oneMatchPerFile=true"
Set "oneMatchPerFile="
REM Set "subDirs=/R"
Set "subDirs="
REM Set "matchWholeLine=true"
Set "matchWholeLine="
REM Set "lineNumbers=true"
Set "lineNumbers="
REM Set "hideMatchingLines=true"
Set "hideMatchingLines="
:args
If "%~1" EQU "/?" (
REM Replace '.' here and above with a tab for an invisible marker.
Call %0 /H /X /1 "BEGIN DOCUMENTATION" "END DOCUMENTATION" "%~f0"
Goto :EOF
) Else If /I "%~1"=="/H" (
SHIFT & Set "hideMatchingLines=true" & Goto :args
) Else If /I "%~1"=="/H-" (
SHIFT & Set "hideMatchingLines=" & Goto :args
) Else If /I "%~1"=="/N" (
SHIFT & Set "lineNumbers=true" & Goto :args
) Else If /I "%~1"=="/N-" (
SHIFT & Set "lineNumbers=" & Goto :args
) Else If /I "%~1"=="/S" (
SHIFT & Set "subdirs=/R" & Goto :args
) Else If /I "%~1"=="/S-" (
SHIFT & Set "subdirs=" & Goto :args
) Else If /I "%~1"=="/X" (
SHIFT & Set "matchWholeLine=true" & Goto :args
) Else If /I "%~1"=="/X-" (
SHIFT & Set "matchWholeLine=" & Goto :args
) Else If /I "%~1"=="/1" (
SHIFT & Set "oneMatchPerFile=true" & Goto :args
) Else If /I "%~1"=="/1-" (
SHIFT & Set "oneMatchPerFile=" & Goto :args
)
Set arg=%1
If DEFINED arg (Set "start=%~1") Else (Set "start=")
Set arg=%2
If DEFINED arg (Set "end=%~2") Else (Set "end=")

:Work Cycle through each filespec
Set "file=%~3"
SHIFT
If DEFINED file (
For %subdirs% %%f in (%file%) Do (
If EXIST "%%~f" (
Echo===== %%f ====>&3
Call :GetLines "%start%" "%end%" "%%f"
)
)
) Else (REM Pipe or redirection.
Call :GetLines "%start%" "%end%"
)
If NOT "%3"=="" Goto :Work
Goto :EOF

::::::::::::::::::::::::::
:GetLines start end file
SetLocal EnableExtensions DisableDelayedExpansion
REM Jeb's 'Echo=!print:*:=!' method might serve better
REM then calculating an offset and removing that portion
REM of the line but I have not tested it yet.
Set /A "L=0, N=10, O=2"
Set "flag="
Set "break="
For /F "delims=" %%T in ('FindStr /n "^" %3') Do (
Set /A "L+=1, t=N, N*=1+L/N*9, O=O+N/t/10"
Set "line=%%T"
Call :PrintLines %1 %2
If DEFINED break Goto :GetLines.break
)
:GetLines.break
Goto :EOF
::::::::::::::::::::::::::
:PrintLines start end
SetLocal EnableExtensions EnableDelayedExpansion
Set "match="
For /L %%i in (!O!,1,!O!) Do Set "line=!line:~%%i!"
If DEFINED flag (
If DEFINED end (
If DEFINED matchWholeLine (
If "!line!" EQU "%~2" (Set "match=true")
) Else (
If "!line!" EQU "" (
If "%~2" EQU "" (Set "match=true")
) Else If "!line!" NEQ "!line:%~2=!" (
Set "match=true"
)
)
)
If DEFINED match (
Set "flag="
If DEFINED oneMatchPerFile Set "break=true"
If NOT DEFINED hideMatchingLines (
If DEFINED lineNumbers (Set /P "=!L!:"<NUL:)
Echo(!line!
)
) Else (
If DEFINED lineNumbers (Set /P "=!L!:"<NUL:)
Echo(!line!
)
) Else (
If DEFINED matchWholeLine (
If "!line!" EQU "%~1" Set "match=true"
) Else (
If "!line!" EQU "" (
If "%~1" EQU "" (Set "match=true")
) Else If "!line!" NEQ "!line:%~1=!" (
Set "match=true"
)
)
If DEFINED match (
If NOT DEFINED hideMatchingLines (
If DEFINED lineNumbers (Set /P "=!L!:"<NUL:)
Echo(!line!
)
Set "flag=on"
)
)
EndLocal & Set "flag=%flag%" & Set "break=%break%"
Goto :EOF
:: END SCRIPT
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

jeb

unread,
May 29, 2012, 4:54:45 AM5/29/12
to
On 28 Mai, 14:52, "Frank P. Westlake" <frank.westl...@gmail.net>
wrote:
> :: BEGIN SCRIPT
...
> Set /A "L+=1, t=N, N*=1+L/N*9, O=O+N/t/10"
...
> For /L %%i in (!O!,1,!O!) Do Set "line=!line:~%%i!"

Ok, it removes the number and the colon, but why so complex?

Why not only?
set "line=!line:*:=!"

jeb

Frank P. Westlake

unread,
Jun 2, 2012, 10:20:04 AM6/2/12
to
On 2012-05-29 01:54, jeb wrote:
>Why not only?
>set "line=!line:*:=!"

I took a few minutes and tried it again and it does work as a direct
replacement. Maybe I overlooked something the last time I tried it. If
that change is made then ":GetLines" can be made EnableDelayedExpansion
and ":PrintLines" can be moved back into ":GetLines", making the script
smaller and faster. But it works now so I won't spend any more time on it.

Frank

Frank P. Westlake

unread,
Jun 5, 2012, 9:53:36 AM6/5/12
to
I just noticed that my previous reply to Jeb's query is missing from my
news server. It doesn't matter now but it helps in understanding the
above to know that I replied saying that 'set "line=!line:*:=!"' did not
work when I tried it in the script.

Frank

Abhijat

unread,
Jun 7, 2012, 6:01:43 AM6/7/12
to
Thanks Frank and everyone else for contributing .. I would have thought there is a much simpler way to get around 'tail' command in dos. Although I appreciate the snippet sent across by Frank, I am unlikely to use it because I could not understand the whole of it and its too big for me.
Here is my initial query -
I can find out what I have to extract from a text file using
For /f "tokens=1 delims=:" %%a in ('findstr /n / c:"Old Identifier" %filename%') do set head=%%a set /a rowstart=head+2
Similarly, I can get rowend as well.
My question is - how can I extract all the rows between start and end and save the file .
Can you please share a simple and smaller solution to it.

Thanks very much,
Abhijat.

foxidrive

unread,
Jun 7, 2012, 9:44:28 AM6/7/12
to
On Thursday 24/05/2012 00:27, Abhijat wrote:
> Hi Mic,
> Sed does not work for me. I use XP professional.

This works here. What problem did you have?
Do you have GnuSED ?


@echo off

(
echo 111
echo 222
echo aaa
echo 333
echo 444
echo bbb
echo 555
) > file.txt


for /f "delims=:" %%a in ('findstr /n "aaa" "file.txt"') do set /a start=%%a+1
for /f "delims=:" %%a in ('findstr /n "bbb" "file.txt"') do set /a end=%%a-1

Tom Lavedas

unread,
Jun 7, 2012, 10:26:07 AM6/7/12
to
On Jun 7, 6:01 am, Abhijat <ursabhi...@gmail.com> wrote:
> Thanks Frank and everyone else for contributing .. I would have thought there is a much simpler way to get around 'tail' command in dos. Although I appreciate the snippet sent across by Frank, I am unlikely to use it because I could not understand the whole of it and its too big for me.
> Here is my initial query -
> I can find out what I have to extract from a text file using
> For /f "tokens=1 delims=:" %%a in ('findstr /n / c:"Old Identifier" %filename%') do set head=%%a set /a rowstart=head+2
> Similarly, I can get rowend as well.
> My question is - how can I extract all the rows between start and end and save the file .
> Can you please share a simple and smaller solution to it.
>
> Thanks very much,
> Abhijat.
>
>
>
> On Tuesday, June 5, 2012 9:53:36 AM UTC-4, Frank P. Westlake wrote:
> > On 2012-06-02 07:20, Frank P. Westlake wrote:
> > > On 2012-05-29 01:54, jeb wrote:
> > >  >Why not only?
> > >  >set "line=!line:*:=!"
{snip}

Maybe a hybrid WSH(VBS)/batch script would help. Keying off of
foxidrive's approach of creating a text file and your FOR statements,
this sample illustrates
the hybrid use of a VBS script to actually use the numbers to output
the proper lines ...

@echo off
setlocal

(
echo 111
echo 222
echo aaa
echo 333
echo 444
echo 555
echo 666
echo bbb
echo 777
echo bbb
echo aaa
) > %temp%.\file.txt

for /f "delims=:" %%a in ('findstr /n "aaa" "%temp%.\file.txt"') do
(
set /a rowstart=%%a
goto:next1
)
:Next1
for /f "delims=:" %%a in ('findstr /n "bbb" "%temp%.\file.txt"') do
(
set /a rowend=%%a
goto:next2
)
:Next2
(
echo for i=1 to wsh.arguments(0^): wsh.stdin.skipline : next
echo for i=2 to wsh.arguments(1^)-wsh.arguments(0^)
echo wsh.echo wsh.stdin.readline
echo next
) > %temp%.\_tmp.vbs
cscript //nologo %temp%.\_tmp.vbs %rowstart% %rowend% < %temp%.
\file.txt
for %%F in (file.txt _tmp.vbs) do del %temp%.\%%F

I think it's simple enough to understand.

Not that I added the two GOTOs to guard against the possibilty that
the search string(s) exists in more than one place in the input file
(file.txt in this case).
___________________________
Tom Lavedas

Todd Vargo

unread,
Jun 7, 2012, 4:42:03 PM6/7/12
to
On 6/7/2012 6:01 AM, Abhijat wrote:
> Thanks Frank and everyone else for contributing .. I would have thought there is a much simpler way to get around 'tail' command in dos. Although I appreciate the snippet sent across by Frank, I am unlikely to use it because I could not understand the whole of it and its too big for me.
> Here is my initial query -
> I can find out what I have to extract from a text file using
> For /f "tokens=1 delims=:" %%a in ('findstr /n / c:"Old Identifier" %filename%') do set head=%%a set /a rowstart=head+2
> Similarly, I can get rowend as well.
> My question is - how can I extract all the rows between start and end and save the file .
> Can you please share a simple and smaller solution to it.
>
> Thanks very much,
> Abhijat.

I already posted some code for you. Did you try it? Was there a problem
with it? Did it not work for you? I wont know unless you report back.

frank.w...@gmail.com

unread,
Jun 7, 2012, 2:32:13 PM6/7/12
to
From Abhijat :
>Can you please share a simple and smaller
>solution to it.

I normally only provide generalized solutions which
anyone can make use of. I don't wish to write custom
scripts unless I am paid to do so for scripts which will
bring profit the receiver, or unless the script is part
of a freeware project. In both cases the project must be
morally acceptable to me. I am retired and have never
been a professional programmer so I won't accept paid
work -- that leaves morally acceptable freeware.

Frank

Tom Lavedas

unread,
Jun 8, 2012, 5:59:41 PM6/8/12
to
On Jun 7, 10:26 am, Tom Lavedas <tglba...@verizon.net> wrote:
> On Jun 7, 6:01 am, Abhijat <ursabhi...@gmail.com> wrote:
>

A 'pure batch' solution that is "simpler' (I think) ...

@echo off

:: Makes a dummy test file
(
echo 111
echo 222
echo aaa]
echo 333%%
echo !444!!
echo.
echo 555 ^^^>
echo ]666 *??
echo bbb
echo 777
echo bbb
echo aaa
) | find /v /n "" > %temp%.\file.txt

:: The working part of the procedure start
setlocal
find /v /n "" < %temp%.\file.txt > %temp%.\_tmp.txt
for /f "delims=:" %%a in (
'findstr /n "aaa" ^< "%temp%.\_tmp.txt"') do (
set /a rowstart=%%a+1
goto:next1 limits search to first occurrence
)
:Next1
for /f "delims=:" %%a in (
'findstr /n "bbb" ^< "%temp%.\_tmp.txt"') do (
set /a rowend=%%a-1
goto:next2 limits search to first occurrence
)
:Next2
for /l %%N in (%rowstart%, 1, %rowend%) do (
for /f "delims=" %%a in (
'find "[%%N]" ^< "%temp%.\file.txt"'
) do (set "Line=%%a"
call set /p ="%%Line:*]=%%"<nul&echo.)
)
del %temp%.\_tmp.txt
:: The working part of the procedure end

:: Removes the dummy test file
del %temp%.\file.txt

It seems to handle most 'poison characters', though I've only tested a
few of the most obvious ones.
_____________________________
Tom Lavedas

jeb

unread,
Jun 8, 2012, 6:22:33 PM6/8/12
to
You could add this between 666 and bbb
echo ^^^^^^^^^^^^^^^^"^^^^"
echo abc^^^&"&
echo spaces in front

All three lines fails more or less, the spaces are stripped at Vista
and Win7.
The carets are unbalanced (in the file they are balanced)
The ampersand will fail completely.

IMHO this can be best solved with delayed expansion.

jeb

Tom Lavedas

unread,
Jun 9, 2012, 9:12:50 AM6/9/12
to
> jeb- Hide quoted text -
>
> - Show quoted text -

Delayed expansion has problems with exclamation points, doesn't it?
At least, my attempts to use it did.
______________________________
Tom Lavedas

jeb

unread,
Jun 9, 2012, 2:31:57 PM6/9/12
to
More or less, but if you know how and when delayed expansion works,
there aren't so many problems left.

Expanding a variable with delayed expansion is always absolutly safe,
independent of the content!
The cause is, that delayed expansion is the last phase of the parser,
and after the expansion the characters are not more examined by
anything.
But obviously the for-loop expansion of ex. %%a can't be also the last
phase.
So after expanding %%a the delayed expansion phase follows.
That causes the main problems.

But this can be avoided with toggling the delayed expansion

for /F "delims=" %%a in (myFile.txt) do (
set "line=%%a"
echo %%a - here is %%a safe

setlocal EnableDelayedExpansion
echo !line! This is absolutly safe
echo %%a This would fail if %%a contains exclamations marks, then
also carets are lost
endlocal
)

The delayed expansion phase has a special rule:
If at least one exclamation mark is present in the line carets are
escape characters for the next character,
but quotes haven't any effect in this phase.

This can be seen here
setlocal EnableDelayedExpansion
echo 1 ^^^^ "^^^^"
echo 2 ^^^^ "^^^^" .... !
echo 3 ^^! "^!"

Output
1 ^^ "^^^^"
2 ^ "^^" ....
3 ! "!"

Here you see that the carets are affected first in the "special
character phase" where "&|'()... are parsed.
As quotes are effectuve here, the line 1 will be modified to ^^ "^^^^"
As there isn't an exclamation mark the line will not more modified.
But line 2 has one so it will result to ^ "^^", now the carets also
work inside of quotes


jeb

billious

unread,
Jun 9, 2012, 9:19:48 PM6/9/12
to
For /f skips lines starting with ";"

I posted this solution 17 days ago:

for /f "tokens=1*delims=[]" %%i in (
' find /n /v "" ^<textfile.txt ' ) do (
if %%i geq %start% if %%i leq %end% (
set flag=%%j
if defined flag >>outfile.txt echo %%j
if not defined flag >>outfile.txt echo.
)
)

which I believe only fails with lines starting "]" or "["

OP appears to be unwilling to use 3rd-party utilities or explain why the
other approaches are not usable. There appears to be no pure-batch
approach that will not show sensitivity to some characters.

In the absence of usable feedback, I'll pay this thread no further
attention.

foxidrive

unread,
Jun 9, 2012, 9:33:04 PM6/9/12
to
On Sunday 10/06/2012 11:19, billious wrote:

> For /f skips lines starting with ";"


> OP appears to be unwilling to use 3rd-party utilities or explain why the
> other approaches are not usable. There appears to be no pure-batch
> approach that will not show sensitivity to some characters.

For that reason it is better to use SED or Todd's VBS solution.

> In the absence of usable feedback, I'll pay this thread no further
> attention.

I can't understand why he ignored so many replies and asked again - unless the news server he used is flaky and is missing loads of messages?


--
Mic

Frank P. Westlake

unread,
Jun 12, 2012, 10:08:10 AM6/12/12
to
On 2012-06-09 18:19, billious wrote:

> I posted this solution 17 days ago:
>
> for /f "tokens=1*delims=[]" %%i in (
> ' find /n /v "" ^<textfile.txt ' ) do (
> if %%i geq %start% if %%i leq %end% (
> set flag=%%j
> if defined flag >>outfile.txt echo %%j
> if not defined flag >>outfile.txt echo.
> )
> )

> There appears to be no pure-batch
> approach that will not show sensitivity to some characters.

My script uses the same general principle as yours but I don't think
mine has trouble with any characters. I didn't run a test for all
characters though, I only looked to see that the characters '!' and '%'
were properly reproduced in the output. So if there are no problems with
it then my script could be reduced to not much more then yours by any
programmer who desires it.

Frank

foxidrive

unread,
Jun 12, 2012, 11:25:48 AM6/12/12
to
On Thursday 07/06/2012 20:01, Abhijat wrote:
> My question is - how can I extract all the rows between start and end and save the file .
> Can you please share a simple and smaller solution to it.
>
> Thanks very much,
> Abhijat.

Abhijat, do you read any of the posts made here?


--
Mic
0 new messages