Display last line of a text file

  • Thread starter Thread starter fpschultze
  • Start date Start date
F

fpschultze

Hello.

Here comes a batch file that shows how to read the last line of a text
file:

=====
@Echo Off

If %1!==! (
Echo Read and display the last line of a text file
Echo.
Echo Syntax: %~n0 filename.txt
Goto :EOF)

If Not Exist %1 (
Echo File not found - %1
Goto :EOF)

SetLocal

::String that will be used to identify the last line
Set
_=vb043527nc502374v520345c7n20345vb7230457c2n305v72b345v02n3v50237cb230b5v

::Copy the file to the temp folder
Copy %1 %temp%.\tmp.tmp >NUL

::Append unique identifier string to the end of the temp file
Echo %_% >> %temp%.\tmp.tmp

::Determine the line number of the last line
For /F "delims=[]" %%a In ('Find /N "%_%" ^< %temp%.\tmp.tmp') Do Set
_=%%a

::Set lastline variable to the line next to last line of the original
file
Set /A _ -= 2
For /F "Tokens=* Skip=%_%" %%A In (%1) Do Set lastline=%%a

::Cleanup
If Exist %temp%.\tmp.tmp Del %temp%.\tmp.tmp

::Display line
Echo %lastline%

EndLocal
=====

Have fun
 
Hello.

Here comes a batch file that shows how to read the last line of a text
file:

Does W2K have the more extensions of XP?

@echo off
setlocal EnableExtensions
for /f %%a in ('find /c /v "" ^< %1') do set /a var=%%a-1
more +%var% %1
 
Seems a lot of work just to find the last line. Brute force seems to work
for me.

for /f "delims=" %%s in (%1) do set LASTLINE=%%s
echo %LASTLINE%

Maybe I don't understand the problem. Also, if the set statement above
doesn't work, there's always echo %%s > %TEMP%\lastline.tmp, then reading
that file's only line into LASTLINE. I don't understand the need to run
FIND.
 
23} How do I get the n'th, the first and the last line of a text file?
24} How do I get the m'th item on the n'th line of a text file?

144994 Dec 7 2005 ftp://garbo.uwasa.fi/pc/link/tscmd.zip
tscmd.zip Useful NT/2000/XP script tricks and tips, T.Salmi

All the best, Timo
 
Seems a lot of work just to find the last line. Brute force seems to work
for me.

for /f "delims=" %%s in (%1) do set LASTLINE=%%s
echo %LASTLINE%

Maybe I don't understand the problem. Also, if the set statement above
doesn't work, there's always echo %%s > %TEMP%\lastline.tmp, then reading
that file's only line into LASTLINE. I don't understand the need to run
FIND.

It just shows that there's more than one way to skin a cat. :)
 
In alt.msdos.batch.nt Harlan Grove said:
Seems a lot of work just to find the last line. Brute force seems to work
for me.
for /f "delims=" %%s in (%1) do set LASTLINE=%%s
echo %LASTLINE%
Maybe I don't understand the problem. Also, if the set statement above
doesn't work, there's always echo %%s > %TEMP%\lastline.tmp, then reading
that file's only line into LASTLINE. I don't understand the need to run
FIND.

Both SET and ECHO have problems when the last line contains "<" or ">".
 
foxidrive said:
It just shows that there's more than one way to skin a cat. :)

LOL. And sometimes skinning a cat is a good description of the convolutions
it takes to do some things in batch!

/Al
 
Both SET and ECHO have problems when the last line contains "<" or ">".

Too true. Other characters can cause problems as well. I doubt it is
possible to have a routine to accurately get the last line of a text
file 100% of the time with only pure batch techniques. Though Herbert
will likely provide a .com creator for this issue (which would be
welcome), 16 bit apps don't work in 64 bit machines, AFAIK.

One can quote the string to handle redirection characters, but that
technique fails if the string has quotes within it. Strings with a
single set of double-quotes in the middle along with redirection
characters are very difficult to handle, such as:

This is > a very " slippery < string.

Ampersands in the string can cause unwanted behavior, if the
sub-string that follows contains valid commands, such as:

This is a test & del *.*

VBscript/WSH may be a better way to tackle this for a built-in
solution. Tom (welcome back), Al and others discussed this recently
in another group.

http://groups.google.com/group/micr...6bb0c44e3ed/7005343ff7cadd12#7005343ff7cadd12

Cheers,
Clay Calvert
(e-mail address removed)
Replace "Z" with "L"
 
fup2 microsoft.public.win2000.cmdprompt.admin set, since FOR /F is
available on NT++ only.
Both SET and ECHO have problems when the last line contains "<" or ">".

And FOR will dissect %1 if it contains blanks, or use it literal when
properly enclosed in quotes.
Unfortunately one can't write "%~1" or '%~1' since both "" and '' have
special meaning with FOR /F.

Strange beast that cat is...
Stefan
 
What code would I need to display contents of line x from the bottom? e.g.
the sixth line from the bottom?

Don
 
Don said:
What code would I need to display contents of line x from the bottom? e.g.
the sixth line from the bottom?

Don
- - - - - - - - - begin screen capture WinXP - - - - - - - - -
C:\cmd>tail %temp%\prodschedlog.txt
"Find New BFSGL10 Jobs.job" (wscript.exe)
Started 8/10/2005 7:50:00 AM
"Check COA DB Load - Tue-Sat.job" (cmd.exe)
Finished 8/10/2005 7:50:04 AM
Result: The task completed with an exit code of (0).
"Find New BFSGL10 Jobs.job" (wscript.exe)
Finished 8/10/2005 7:50:18 AM
Result: The task completed with an exit code of (0).
"Check COA DB Load - Tue-Sat.job" (cmd.exe)
Started 8/10/2005 8:00:00 AM
"Send GL E-Mail.job" (wscript.exe)
Started 8/10/2005 8:00:00 AM
"Check COA DB Load - Tue-Sat.job" (cmd.exe)
Finished 8/10/2005 8:00:04 AM
Result: The task completed with an exit code of (0).

C:\cmd>demo\ReadFromEndOfFile %temp%\prodschedlog.txt
File c:\temp\prodschedlog.txt has 406 lines.
The requested line is Started 8/10/2005 8:00:00 AM

C:\cmd>wyllist c:\cmd\demo\ReadFromEndOfFile.cmd
==========begin file c:\cmd\demo\ReadFromEndOfFile.cmd ==========
01. @echo off
02. setlocal
03. for /f %%a in ('find /v /c "" ^< %1') do set linecount=%%a
04. set /a firstline = linecount - 6
05. more /e +%firstline% %1 > %temp%\w0rkf1l3.$$$
06. set /p line.lastminussix=<%temp%\w0rkf1l3.$$$
07. del %temp%\w0rkf1l3.$$$
08. echo/File %1 has %linecount% lines.
09. echo/The requested line is %line.lastminussix%
==========end file c:\cmd\demo\ReadFromEndOfFile.cmd ==========
- - - - - - - - - end screen capture WinXP - - - - - - - - -
 
Don Grainger said:
What code would I need to display contents of line x from the bottom? e.g.
the sixth line from the bottom?
....

Reinventing tail by brute force.


@REM bt.cmd
@echo off
if not .%1. == ... (cmd /V:ON /C %0 . %1 %2 & goto :EOF)
for /F %%a in ('type "%3"') do (
for /L %%i in (%2,-1,1) do (
set /A j=%%i-1
if %%i == 1 (
echo %%a > "%0.temp.1"
) else (
copy "%0.temp.!j!" "%0.temp.%%i" > nul
)
)
)
type "%0.temp.%2"
del "%0.temp."*


Use as bt 6 yourfile.
 
Don said:
What code would I need to display contents of line x from the bottom? e.g.
the sixth line from the bottom?

Don

Hello.

Here comes a batch file that shows how to read the last line of a text
file:

=====
@Echo Off

If %1!==! (
Echo Read and display the last line of a text file
Echo.
Echo Syntax: %~n0 filename.txt
Goto :EOF)

If Not Exist %1 (
Echo File not found - %1
Goto :EOF)

SetLocal

::String that will be used to identify the last line
Set
_=vb043527nc502374v520345c7n20345vb7230457c2n305v72b345v02n3v50237cb230b5v

::Copy the file to the temp folder
Copy %1 %temp%.\tmp.tmp >NUL

::Append unique identifier string to the end of the temp file
Echo %_% >> %temp%.\tmp.tmp

::Determine the line number of the last line
For /F "delims=[]" %%a In ('Find /N "%_%" ^< %temp%.\tmp.tmp') Do Set
_=%%a

::Set lastline variable to the line next to last line of the original
file
Set /A _ -= 2
For /F "Tokens=* Skip=%_%" %%A In (%1) Do Set lastline=%%a

::Cleanup
If Exist %temp%.\tmp.tmp Del %temp%.\tmp.tmp

::Display line
Echo %lastline%

EndLocal
=====

Have fun

Here's a modified version with checking incorporated.

==========begin file C:\CMD\DEMO\ReadFromEndOfFile.cmd ==========
001. @echo off
002. setlocal enabledelayedexpansion
003. ::
004. :: parms -- %%1 the name of the input file
005. :: %%2 the nth from last line
006. ::
007. if not exist "%~1" (
008. echo/File %1 does not exist.
009. goto :EOF
010. )
011. if "%2" equ "" (
012. echo/Enter number of the nth from last line to be read.
013. goto :EOF
014. )
015. echo %2|findstr /r "[^0-9]">nul
016. if %errorlevel% equ 0 (
017. echo/The 'number' you entered - "%2" - contains non-numeric characters.
018. goto :EOF
019. )
020. for /f %%a in ('find /v /c "" ^< %1') do set /a linecount=%%a
021. if %2 gtr %linecount% (
022. echo/The number you entered - "%2" - is greater than the number of^
023. lines in the designated file.
024. goto :EOF
025. )
026. set /a firstline = linecount - %2
027. more /e +%firstline% %1 > %temp%\w0rkf1l3.$$$
028. set /p line.lastminus%2=<%temp%\w0rkf1l3.$$$
029. del %temp%\w0rkf1l3.$$$
030. echo/File %1 has %linecount% lines.
031. echo/The requested line is !line.lastminus%2!
==========end file C:\CMD\DEMO\ReadFromEndOfFile.cmd ==========

For big files, using 'more /e +<startline>' and then reading the
first line of the resultant file with 'set /p' could prove to be
faster, especially if the value of <last-n> is large.
 
Phil Robyn said:
For big files, using 'more /e +<startline>' and then reading the
first line of the resultant file with 'set /p' could prove to be
faster, especially if the value of <last-n> is large.

But if the OP has really big files and needs to do this regularly, better to
find a tool that opens the file, immediately seeks to the end of it, then
reads the file back to front until it gets to the desired line. Like the
tail command you showed in your other response.

There's also a question whether blank lines at the end of the file should be
ingored or not.
 
You can make your cmd much more powerfull if you install Linux/Unix
commands from www.cygwin.com.

A good tool for your problem, e.g. the last n lines, is "tail".

M:\>tail --help
Usage: tail [OPTION]... [FILE]...
Print the last 10 lines of each FILE to standard output.
With more than one FILE, precede each with a header giving the file
name.
With no FILE, or when FILE is -, read standard input.

Mandatory arguments to long options are mandatory for short options
too.
--retry keep trying to open a file even if it is
inaccessible when tail starts or if it
becomes
inaccessible later; useful when following by
name,
i.e., with --follow=name
-c, --bytes=N output the last N bytes
-f, --follow[={name|descriptor}]
output appended data as the file grows;
-f, --follow, and --follow=descriptor are
equivalent
-F same as --follow=name --retry
-n, --lines=N output the last N lines, instead of the last
10
--max-unchanged-stats=N
with --follow=name, reopen a FILE which has
not
changed size after N (default 5) iterations
to see if it has been unlinked or renamed
(this is the usual case of rotated log
files)
--pid=PID with -f, terminate after process ID, PID
dies
-q, --quiet, --silent never output headers giving file names
-s, --sleep-interval=S with -f, sleep for approximately S seconds
(default 1.0) between iterations.
-v, --verbose always output headers giving file names
--help display this help and exit
--version output version information and exit

If the first character of N (the number of bytes or lines) is a `+',
print beginning with the Nth item from the start of each file,
otherwise,
print the last N items in the file. N may have a multiplier suffix:
b 512, k 1024, m 1024*1024.

With --follow (-f), tail defaults to following the file descriptor,
which
means that even if a tail'ed file is renamed, tail will continue to
track
its end. This default behavior is not desirable when you really want
to
track the actual name of the file, not the file descriptor (e.g., log
rotation). Use --follow=name in that case. That causes tail to track
the
named file by reopening it periodically to see if it has been removed
and
recreated by some other program.

Report bugs to <[email protected]>.
 
You can make your cmd much more powerfull if you install Linux/Unix
commands from www.cygwin.com.

While Cygwin is a very useful too in itself (would you believe running
KDE under Xfree86 under Cygwin under XP?), some of the utilities
require that the actual Cygwin package be installed. A very complete
set of utilities, most of which work, that does not require Cygwin,
though some may require other DLLs, is the CoreUtils package from
<http://gnuwin32.sourceforge.net/packages.html>.
 
Back
Top