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

How do I get the n:th, the first and the last line of a text file?

14 views
Skip to first unread message

Timo Salmi

unread,
Jan 1, 2004, 4:24:33 AM1/1/04
to
Revisiting that item from

56675 Dec 27 2003 ftp://garbo.uwasa.fi/pc/link/tscmd.zip
tscmd.zip Useful NT/2000/XP script tricks and tips, T.Salmi

I note, with particular compliments to Al Dunbar and Phil Robyn,
that the SET /P techniques they have come up with and demonstrated
can well be fitted as one of the options for also these tasks.
Tested in Windows XP [Version 5.1.2600]

------------------------------------------------------------------------
(snip: The subroutine examples already there)

There are other options like
@echo off & setlocal enableextensions
:: Make a test file
for %%f in (mytest.txt mytemp.txt) do if exist %%f del %%f
for %%f in (1 2 3 4 5 6 7 8 9) do echo This is line %%f>>mytest.txt
::
:: Special get the first line of a file
set /p line_=<mytest.txt
echo %line_%
::
:: Special get the last file of a file
for /f "delims=" %%r in ('type mytest.txt') do set line_=%%r
echo %line_%
::
:: Special get the Nth line
set /a n_=5-1
for /f "skip=%n_% delims=" %%r in ('type mytest.txt') do echo %%r>>mytemp.txt
set /p line_=<mytemp.txt
echo %line_%
::
:: Clean up
for %%f in (mytest.txt mytemp.txt) do if exist %%f del %%f
endlocal & goto :EOF

The output is
D:\TEST>cmdfaq
This is line 1
This is line 9
This is line 5

(snip: A few new words on the alternative SED and GAWK batch
solution pointers to these same tasks.)
------------------------------------------------------------------------

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland
Timo's FAQ materials at http://www.uwasa.fi/~ts/http/tsfaq.html

Phil Robyn

unread,
Jan 1, 2004, 4:49:50 AM1/1/04
to
Timo Salmi wrote:

> Revisiting that item from
>
> 56675 Dec 27 2003 ftp://garbo.uwasa.fi/pc/link/tscmd.zip
> tscmd.zip Useful NT/2000/XP script tricks and tips, T.Salmi
>
> I note, with particular compliments to Al Dunbar and Phil Robyn,
> that the SET /P techniques they have come up with and demonstrated
> can well be fitted as one of the options for also these tasks.
> Tested in Windows XP [Version 5.1.2600]
>
> ------------------------------------------------------------------------

<<<<snip>>>>


> ::
> :: Special get the last file of a file
> for /f "delims=" %%r in ('type mytest.txt') do set line_=%%r
> echo %line_%

The preceding will be *extremely* slow if the file is large. Here's a
much faster way to get the last line of a large file:

- - - - - - - - - - begin screen capture - - - - - - - - - -
<Win2000> c:\cmd>rlist demo\TestGetLastLine1.cmd
=====begin c:\cmd\demo\TestGetLastLine1.cmd ====================
1. @echo off
2. for /f %%a in ('find /v /c "" ^< %1') do set /a linecount=%%a
3. set /a linecount-=1
4. for /f "tokens=*" %%a in ('more /e +%linecount% %1') do set last_line=%%a
=====end c:\cmd\demo\TestGetLastLine1.cmd ====================

<Win2000> c:\cmd>dir d:\junkdir\glemail.log | find "/"
08/04/01 04:57p 1,810,937 glemail.log

<Win2000> c:\cmd>reccount d:\junkdir\glemail.log .
File d:\junkdir\glemail.log has 16949 records.

<Win2000> c:\cmd>echo %time% & demo\TestGetLastLine1 d:\junkdir\glemail.log & echo !time!
1:45:43.05
1:45:43.93

<Win2000> c:\cmd>set last_line
last_line=2001/08/04 15:01:13.30 GLEMAIL5 ************************ ENDED *****************************
- - - - - - - - - - end screen capture - - - - - - - - - -

--
Phil Robyn
Univ. of California, Berkeley

u n z i p m y a d d r e s s t o s e n d e - m a i l

Timo Salmi

unread,
Jan 1, 2004, 5:30:07 AM1/1/04
to
Phil Robyn <zipp...@uclink.berkeley.edu> wrote:

> Timo Salmi wrote:
> > :: Special get the last file of a file
> > for /f "delims=" %%r in ('type mytest.txt') do set line_=%%r
> The preceding will be *extremely* slow if the file is large. Here's a
> much faster way to get the last line of a large file:

Thanks Phil. I suspected as much.

> =====begin c:\cmd\demo\TestGetLastLine1.cmd ====================
> 1. @echo off
> 2. for /f %%a in ('find /v /c "" ^< %1') do set /a linecount=%%a
> 3. set /a linecount-=1
> 4. for /f "tokens=*" %%a in ('more /e +%linecount% %1') do set last_line=%%a

Included suitably edited to fit with the rest of the item, naturally
with the acknowledgement.

I wonder if that somehow could be utilized to also have a faster way
to get the N:th line.

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland

Useful script files and tricks ftp://garbo.uwasa.fi/pc/link/tscmd.zip

Uno

unread,
Jan 1, 2004, 7:08:38 AM1/1/04
to

> 2. for /f %%a in ('find /v /c "" ^< %1') do set /a linecount=%%a

In one of my recent postings I used:

>nul for /f "tokens=1 delims=:" %%a in ('findstr /n "\<*" "%1"') do set n=%%a

Do you think your method is faster?

Uno

unread,
Jan 1, 2004, 7:09:00 AM1/1/04
to
Sorry:

Uno

unread,
Jan 1, 2004, 7:12:33 AM1/1/04
to
> :: Special get the last file of a file

?


Uno

unread,
Jan 1, 2004, 8:31:55 AM1/1/04
to

"Uno" <nos...@sfth.net> wrote in message news:a5UIb.27586$VW.12...@news3.tin.it...

try this one:

@echo off
echo %time%>test_time.txt


for /f "tokens=1 delims=:" %%a in ('findstr /n "\<*" "%1"') do set n=%%a

echo %n%
echo %time%>>test_time.txt
for /f %%a in ('find /v /c "" ^<%1') do set linecount=%%a
echo %linecount%
echo %time%>>test_time.txt


Timo Salmi

unread,
Jan 1, 2004, 8:51:37 AM1/1/04
to
In article <w5UIb.27587$VW.12...@news3.tin.it>, Uno <nos...@sfth.net> wrote:
> for /f "tokens=1 delims=:" %%a in ('findstr /n "\<*" "%1"') do set n=%%a

That line count version gives me the idea for yet one formulation
for getting the Nth line:

@echo off & setlocal enableextensions enabledelayedexpansion


:: Make a test file
for %%f in (mytest.txt mytemp.txt) do if exist %%f del %%f
for %%f in (1 2 3 4 5 6 7 8 9) do echo This is: line %%f>>mytest.txt
::

set /a GetLineNumber=5
for /f "tokens=1,* delims=:" %%a in ('findstr /n "\<*" "mytest.txt"') do (
set /a LineCount_=%%a
if !LineCount_! EQU %GetLineNumber% set line_=%%b)


echo %line_%
::
:: Clean up
for %%f in (mytest.txt mytemp.txt) do if exist %%f del %%f
endlocal & goto :EOF

The output will be
D:\TEST>cmdfaq
This is: line 5

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland

Timo Salmi

unread,
Jan 1, 2004, 8:56:54 AM1/1/04
to
In article <fjVIb.33812$_P.14...@news4.tin.it>, Uno <nos...@sfth.net> wrote:
> try this one:
> @echo off
> echo %time%>test_time.txt
> for /f "tokens=1 delims=:" %%a in ('findstr /n "\<*" "%1"') do set n=%%a
> echo %n%
> echo %time%>>test_time.txt
> for /f %%a in ('find /v /c "" ^<%1') do set linecount=%%a
> echo %linecount%
> echo %time%>>test_time.txt

In a single test the latter was marginally faster for a file with a
1000 lines.

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland

Phil Robyn

unread,
Jan 1, 2004, 11:44:42 AM1/1/04
to
Timo Salmi wrote:
> In article <fjVIb.33812$_P.14...@news4.tin.it>, Uno <nos...@sfth.net> wrote:
>
>>try this one:
>>@echo off
>>echo %time%>test_time.txt
>>for /f "tokens=1 delims=:" %%a in ('findstr /n "\<*" "%1"') do set n=%%a
>>echo %n%
>>echo %time%>>test_time.txt
>>for /f %%a in ('find /v /c "" ^<%1') do set linecount=%%a
>>echo %linecount%
>>echo %time%>>test_time.txt
>
>
> In a single test the latter was marginally faster for a file with a
> 1000 lines.
>
> All the best, Timo
>

Hi, Timo and Uno:

Following is a comparison of the three methods on a file of moderate size.
The first two methods are roughly equivalent; the third is significantly
faster. I would hate to try either of the first two methods on large files.

- - - - - - - - - - begin screen capture - - - - - - - - - -

<Win2000> c:\cmd>dir d:\banway\2003-12-31.log | find "/"
01/01/04 02:02a 174,878 2003-12-31.log

<Win2000> c:\cmd>reccount d:\banway\2003-12-31.log .
File d:\banway\2003-12-31.log has 2981 records.

<Win2000> c:\cmd>rlist demo\TestGetLastLine3.cmd
=====begin c:\cmd\demo\TestGetLastLine3.cmd ====================
1. @echo off
2. echo %time%
3. for /f "tokens=1 delims=:" %%a in ('findstr /n "\<*" "%1"') do set n=%%a
4. echo %time%
=====end c:\cmd\demo\TestGetLastLine3.cmd ====================

<Win2000> c:\cmd>demo\TestGetLastLine3 d:\banway\2003-12-31.log
8:38:49.72
8:38:53.33

<Win2000> c:\cmd>rlist demo\TestGetLastLine2.cmd
=====begin c:\cmd\demo\TestGetLastLine2.cmd ====================
1. @echo off
2. echo %time%
3. for /f "delims=" %%a in ('type %1') do set last_line=%%a
4. echo %time%
=====end c:\cmd\demo\TestGetLastLine2.cmd ====================

<Win2000> c:\cmd>demo\TestGetLastLine2 d:\banway\2003-12-31.log
8:39:20.60
8:39:24.11

<Win2000> c:\cmd>rlist demo\TestGetLastLine1.cmd
=====begin c:\cmd\demo\TestGetLastLine1.cmd ====================
1. @echo off

2. echo %time%
3. for /f %%a in ('find /v /c "" ^< %1') do set /a linecount=%%a
4. set /a linecount-=1
5. for /f "tokens=*" %%a in ('more /e +%linecount% %1') do set last_line=%%a
6. echo %time%


=====end c:\cmd\demo\TestGetLastLine1.cmd ====================

<Win2000> c:\cmd>demo\TestGetLastLine1 d:\banway\2003-12-31.log
8:39:47.75
8:39:47.96

Phil Robyn

unread,
Jan 1, 2004, 12:23:57 PM1/1/04
to
Timo Salmi wrote:

> In article <w5UIb.27587$VW.12...@news3.tin.it>, Uno <nos...@sfth.net> wrote:
>
>>for /f "tokens=1 delims=:" %%a in ('findstr /n "\<*" "%1"') do set n=%%a
>
>
> That line count version gives me the idea for yet one formulation
> for getting the Nth line:
>
> @echo off & setlocal enableextensions enabledelayedexpansion
> :: Make a test file
> for %%f in (mytest.txt mytemp.txt) do if exist %%f del %%f
> for %%f in (1 2 3 4 5 6 7 8 9) do echo This is: line %%f>>mytest.txt
> ::
> set /a GetLineNumber=5
> for /f "tokens=1,* delims=:" %%a in ('findstr /n "\<*" "mytest.txt"') do (
> set /a LineCount_=%%a
> if !LineCount_! EQU %GetLineNumber% set line_=%%b)
> echo %line_%
> ::
> :: Clean up
> for %%f in (mytest.txt mytemp.txt) do if exist %%f del %%f
> endlocal & goto :EOF
>
> The output will be
> D:\TEST>cmdfaq
> This is: line 5
>
> All the best, Timo
>

Hi, Timo,

Again, it seems that file size makes an immense difference in the results.

- - - - - - - - - - begin screen capture - - - - - - - - - -

<Win2000> c:\cmd>dir d:\banway\2003-12-31.log | find "/"
01/01/04 02:02a 174,878 2003-12-31.log

<Win2000> c:\cmd>reccount d:\banway\2003-12-31.log .
File d:\banway\2003-12-31.log has 2981 records.

<Win2000> c:\cmd>rlist demo\TestGetNthLine1.cmd
=====begin c:\cmd\demo\TestGetNthLine1.cmd ====================
01. @echo off
02. setlocal
03. echo %time%
04. set GetLineNumber=%1
05. set File=%2
06. for /f "tokens=1,* delims=:" %%a in ('findstr /n "\<*" %File%') do (
07. set /a LineCount_=%%a
08. if !LineCount_! EQU %GetLineNumber% set line_=%%b)
09. echo %line_%
10. echo %time%
=====end c:\cmd\demo\TestGetNthLine1.cmd ====================

<Win2000> c:\cmd>demo\TestGetNthLine1 2899 d:\banway\2003-12-31.log
9:11:24.04
2003-12-31 23:20:00.10 c:\cmd\TEST\heartbeat.cmd started.
9:11:28.38

<Win2000> c:\cmd>rlist demo\TestGetNthLine2.cmd
=====begin c:\cmd\demo\TestGetNthLine2.cmd ====================
01. @echo off
02. setlocal
03. echo %time%
04. set GetLineNumber=%1
05. set File=%2
06. set /a StartAt = GetLineNumber - 1
07. more /e +%StartAt% %File%>w0rkfile.$$$
08. set /p Nth_line=<w0rkfile.$$$
09. del w0rkfile.$$$
10. echo %Nth_line%
11. echo %time%
=====end c:\cmd\demo\TestGetNthLine2.cmd ====================

<Win2000> c:\cmd>demo\TestGetNthLine2 2899 d:\banway\2003-12-31.log
9:11:50.94
2003-12-31 23:20:00.10 c:\cmd\TEST\heartbeat.cmd started.
9:11:51.07

<Win2000> c:\cmd>dir d:\junkdir\glemail.log | find "/"
08/04/01 04:57p 1,810,937 glemail.log

<Win2000> c:\cmd>reccount d:\junkdir\glemail.log .
File d:\junkdir\glemail.log has 16949 records.

<Win2000> c:\cmd>demo\TestGetNthLine1 16001 d:\junkdir\glemail.log
9:12:51.12
2001/07/31 11:02:46.10 GLEMAIL5 downloaded BFS.P.BFPGL10D.GECERROR.D010731.T105737 c:\temp\20010731\GECERROR.D010731.T105737.txt
9:17:05.26

<Win2000> c:\cmd>demo\TestGetNthLine2 16001 d:\junkdir\glemail.log
9:20:33.06
2001/07/31 11:02:46.10 GLEMAIL5 downloaded BFS.P.BFPGL10D.GECERROR.D010731.T105737 c:\temp\20010731\GECERROR.D010731.T105737.txt
9:20:33.76

Timo Salmi

unread,
Jan 1, 2004, 2:52:48 PM1/1/04
to
Phil Robyn <zipp...@uclink.berkeley.edu> wrote:
> Timo Salmi wrote:
> > That line count version gives me the idea for yet one formulation
> > for getting the Nth line:

> Again, it seems that file size makes an immense difference in the results.

> 04. set GetLineNumber=%1


> 05. set File=%2
> 06. set /a StartAt = GetLineNumber - 1
> 07. more /e +%StartAt% %File%>w0rkfile.$$$
> 08. set /p Nth_line=<w0rkfile.$$$
> 09. del w0rkfile.$$$
> 10. echo %Nth_line%

Thank you. That faster alternative is the idea I have been looking
for! The lines 7 and 8 clearly are the ones that essentially do the
trick.

Of course, if one would want really fast, one would use specialized
programs or SED or GAWK. But what you have posted make a very
instructive scripting demonstrations. This is, as it should, more
about scripting e.g. for the FAQ than the actual task. Good.

Timo Salmi

unread,
Jan 2, 2004, 1:19:59 AM1/2/04
to
Phil Robyn <zipp...@uclink.berkeley.edu> wrote:
> Timo Salmi wrote:
> > That line count version gives me the idea for yet one formulation
> > for getting the Nth line:

> Again, it seems that file size makes an immense difference in the results.

> 06. set /a StartAt = GetLineNumber - 1


> 07. more /e +%StartAt% %File%>w0rkfile.$$$
> 08. set /p Nth_line=<w0rkfile.$$$

Below is what I eventually wanted to do. I do hope that I have
managed to pick up the fast components. And thank you, again.

DRAFT

49) I need to reverse a text file. How do I do that fairly quickly?

This item benefits from a discussion in the news:alt.msdos.batch.nt
as per the earlier item #23. The code needed is relatively brief. It
also introduces the use of FOR /L for the first time in this FAQ.

@echo off & setlocal enableextensions

:: Make a test file
set fileName=mytest.txt
for %%f in (%fileName% %temp%\mytemp.txt) do if exist %%f del %%f
for %%f in (1 2 3 4 5 6 7 8 9) do echo This is line %%f>>%fileName%
::
:: Get the number of lines
for /f %%a in ('find /v /c "" ^< %fileName%') do set /a lineCount=%%a
::
for /l %%a in (%lineCount%,-1,1) do call :OutputOneLine %%a
::
:: Clean up
for %%f in (%fileName% %temp%\mytemp.txt) do if exist %%f del %%f
endlocal & goto :EOF

@echo off & setlocal enableextensions
:: ===============================================================
:OutputOneLine
set /a StartAt = %1 - 1
more /e +%StartAt% %fileName%>%temp%\mytemp.txt
set /p Nth_line=<%temp%\mytemp.txt
echo %Nth_line%
endlocal & goto :EOF

The output is
D:\TEST>cmdfaq
This is line 9
This is line 8
This is line 7
This is line 6
This is line 5
This is line 4
This is line 3
This is line 2
This is line 1
--------------------------------------------------------------------

Uno

unread,
Jan 5, 2004, 7:41:28 AM1/5/04
to
> :: Special get the Nth line
> set /a n_=5-1
> for /f "skip=%n_% delims=" %%r in ('type mytest.txt') do echo %%r>>mytemp.txt
> set /p line_=<mytemp.txt
> echo %line_%

Another solution:

set l=
set /a n_=5-1
for /f "tokens=*" %%a in ('more +%n_% ^< mytest.txt') do (if not defined l set "l=%%a")
echo.%l%


0 new messages