17

Any ideas how to echo or type the last 10 lines of a txt file?

I'm running a server change log script to prompt admins to state what they're doing, so we can track changes. I'm trying to get the script to show the last 10 entries or so to give an idea of what's been happening recently. I've found a script that deals with the last line, as shown below, but can't figure out what to change in it to display the last 10 lines. Script:

@echo off
setLocal EnableDelayedExpansion
for /f "tokens=* delims= " %%a in (c:\log09.txt) do (
set var=%%a
)
echo !var!

Example of log file:

06/02/2009, 12:22,Remote=Workstation-9,Local=,
mdb,bouncing box after updates,CAS-08754,
=================
07/02/2009, 2:38,Remote=,Local=SERVER1,
mdb,just finished ghosting c drive,CAS-08776,
=================
07/02/2009, 3:09,Remote=,Local=SERVER1,
mdb,audit of server,CAS-08776,

Any thoughts? The script works great, just need it to pipe more lines to the screen.

Elrond_EGLDer
  • 47,430
  • 25
  • 189
  • 180
  • http://stackoverflow.com/questions/187587/looking-for-a-windows-equivalent-of-the-unix-tail-command – inf3rno Jun 20 '13 at 15:40

10 Answers10

18

Hopefully this will save Joel's eyes :)

@echo OFF

:: Get the number of lines in the file
set LINES=0
for /f "delims==" %%I in (data.txt) do (
    set /a LINES=LINES+1
)

:: Print the last 10 lines (suggestion to use more courtsey of dmityugov)
set /a LINES=LINES-10
more +%LINES% < data.txt
Patrick Cuff
  • 26,370
  • 11
  • 63
  • 93
12

This answer combines the best features of already existing answers, and adds a few twists.

The solution is a simple batch implementation of the tail command.

The first argument is the file name (possibly with path information - be sure to enclose in quotes if any portion of path contains spaces or other problematic characters).

The second argument is the number of lines to print.

Finally any of the standard MORE options can be appended: /E /C /P /S /Tn. (See MORE /? for more information).

Additionally the /N (no pause) option can be specified to cause the output to be printed continuosly without pausing.

The solution first uses FIND to quickly count the number of lines. The file is passed in via redirected input instead of using a filename argument in order to eliminate the printout of the filename in the FIND output.

The number of lines to skip is computed with SET /A, but then it resets the number to 0 if it is less than 0.

Finally uses MORE to print out the desired lines after skipping the unwanted lines. MORE will pause after each screen's worth of lines unless the output is redirected to a file or piped to another command. The /N option avoids the pauses by piping the MORE output to FINDSTR with a regex that matches all lines. It is important to use FINDSTR instead of FIND because FIND can truncate long lines.

:: tail.bat File Num [/N|/E|/C|/P|/S|/Tn]...
::
::   Prints the last Num lines of text file File.
::
::   The output will pause after filling the screen unless the /N option
::   is specified
::
::   The standard MORE options /E /C /P /S /Tn can be specified.
::   See MORE /? for more information
::
@echo OFF
setlocal
set file=%1
set "cnt=%~2"
shift /1
shift /1
set "options="
set "noPause="
:parseOptions
if "%~1" neq "" (
  if /i "%~1" equ "/N" (set noPause=^| findstr "^") else set options=%options% %~1
  shift /1
  goto :parseOptions
)
for /f %%N in ('find /c /v "" ^<%file%') do set skip=%%N
set /a "skip-=%cnt%"
if %skip% lss 0 set skip=0
more +%skip% %options% %file% %noPause%
dbenham
  • 119,153
  • 25
  • 226
  • 353
  • +1 - `find /c /v ""...` is MUCH faster than `find /v /c "%%$%!"...` when the file is very large – ForOhFor Jul 16 '13 at 22:05
  • How to use /N here. I am trying to use this for tail -f kind of functionality. Does /N option does that? – Abibullah Rahamathulah Oct 30 '13 at 14:18
  • @AbibullahRahamathulah - No, there is no equivalent to the `tail -f` option. The `\N` option simply causes the output to flow continuously without pause. Without the `\N` option, the output pauses each time the screen is filled. – dbenham Oct 30 '13 at 14:56
  • @dbenham, Yes I understood that now. I have started using the tail.exe and its working. Thanks for your response. – Abibullah Rahamathulah Oct 30 '13 at 15:32
  • For some reason this script counted only 5442138 lines when the file was actually 44479179 lines long. I fixed it by changing the for loop line to read: for /f %%N in ('type %file% ^| find /c /v ""') do set skip=%%N – rmeakins Jun 11 '14 at 23:58
  • After 65246 lines (of 100000) or 965500 lines (of 1000000) with the `/N` flag, the command prompt stops, but the command doesn't complete. Pressing enter at this point shows one line, but pressing space allows the command to continue to the end. I'm not enough of a batch wizard to figure out what's going on here. – Sinjai Aug 23 '17 at 17:57
  • @Sinjai - That is a known behavior/limitation of the MORE command. So you will have to use some other solution if you are dealing with a large file. – dbenham Aug 23 '17 at 18:37
  • I figured, but what exactly *is* the behavior here? – Sinjai Aug 23 '17 at 18:38
  • @Sinjai - I've never seen any official documentation, nor have I tried to quantify the exact behavior. I've just seen multiple posts that describe problems similar to what you are getting. Normally MORE will not pause when output is piped. But if the number of lines exceeds a threshold around 64K (not sure of the exact number), then it pauses. – dbenham Aug 23 '17 at 19:18
  • Strange. Stranger yet that with 1 million lines, it freezes 96% of the way through. – Sinjai Aug 23 '17 at 19:20
10

You should probably just find a good implementation of tail. But if you really really insist on using CMD batch files and want to run on any NT machine unmolested, this will work:

@echo off
setLocal EnableDelayedExpansion
for /f "tokens=* delims= " %%a in (c:\tmp\foo.txt) do (
set var9=!var8!
set var8=!var7!
set var7=!var6!
set var6=!var5!
set var5=!var4!
set var4=!var3!
set var3=!var2!
set var2=!var1!
set var1=!var!
set var=%%a
)
echo !var9!
echo !var8!
echo !var7!
echo !var6!
echo !var5!
echo !var4!
echo !var3!
echo !var2!
echo !var1!
echo !var!
Joel Spolsky
  • 32,422
  • 17
  • 82
  • 101
  • Hm, that's the kind of straightforward way I never really consider with batch files. But yes, it nibbles away at the eyes. – Joey Oct 23 '09 at 17:19
  • Nice one… but will output blank lines if input file is less than 10 lines long. And… why `delims={space}` not `delims={nothing}`? – Benoit Feb 12 '12 at 19:46
  • This is an interesting brute force approach that can work nicely if the files are cooperative. However, another minor gotcha is that the echo commands may not always print what you expect them to print: since the commands are "eval"ed, any lines beginning with "/?" will display the echo help message instead of the data. – Mattias Andersson Apr 10 '12 at 20:57
  • 1
    @MattiasAndersson That gotcha is avoided with `echo.`, i.e. `echo.!varn!` will avoid that problem. – Mark Hurd Mar 05 '13 at 14:50
4

After trying all of the answers I found on this page none of them worked on my file with 15539 lines.

However I found the answer here to work great. Copied into this post for convenience.

@echo off
for /f %%i in ('find /v /c "" ^< C:\path\to\textfile.txt') do set /a lines=%%i
set /a startLine=%lines% - 10
more /e +%startLine% C:\path\to\textfile.txt

This code will print the last 10 lines in the "C:\path\to\textfile.txt" file.

Credit goes to OP @Peter Mortensen

Community
  • 1
  • 1
Randy Rakestraw
  • 303
  • 1
  • 9
4

There are several windows implementations of the tail command. It should be exactly what you want.

This one sounds particularly good: http://malektips.com/xp_dos_0001.html

They range from real-time monitoring to the last x lines of the file.

Edit: I noticed that the included link is to a package It should work, but here are some more versions:

http://www.lostinthebox.com/viewtopic.php?f=5&t=3801 http://sourceforge.net/projects/tailforwin32

Phil
  • 422
  • 5
  • 18
4

If file is too large it can take too long to get count of lines another way is to use find and pass it a nowhere string

$find /v /c "%%$%!" yourtextfile.txt

this would result an output like this

$---------- yourtextfile.txt: 140

then you can parse output using for like this

$for /f "tokens=3" %i in ('find /v /c "%%$%!" tt.txt') do set countoflines=%i

then you can substract ten lines from the total lines

3

using a single powershell command:

powershell -nologo "& "Get-Content -Path c:\logFile.log -Tail 10"

applies to powershell 3.0 and newer

Eyal
  • 131
  • 1
  • 8
  • You could also create a batch file named TAIL.CMD with this code: powershell -nologo "& "Get-Content -Path %1 -Tail 10" – PollusB May 13 '15 at 15:50
  • Why go through the pain of calling PowerShell from cmd.exe? Just use PowerShell interactively instead of cmd.exe and type the command. – Bill_Stewart Jan 20 '16 at 22:39
  • 1
    the original question asked for a batch script, so i framed my reply as such. – Eyal Jan 31 '16 at 13:14
1

I agree with "You should use TAIL" answer. But it does not come by default on Windows. I suggest you download the "Windows 2003 Resource Kit" It works on XP/W2003 and more.

If you don't want to install on your server, you can install the resource kit on another machine and copy only TAIL.EXE to your server. Usage is sooooo much easier.

C:\> TAIL -10 myfile.txt
PollusB
  • 1,347
  • 1
  • 18
  • 26
1

Here's a utility written in pure batch that can show a lines of file within a given range.To show the last lines use (here the script is named tailhead.bat):

call tailhead.bat -file "file.txt" -begin -10
npocmaka
  • 51,748
  • 17
  • 123
  • 166
0

Any ideas how to echo or type the last 10 lines of a txt file?

The following 3-liner script will list the last n lines from input file. n and file name/path are passed as input arguments.

# Script last.txt
var str file, content ; var int n, count
cat $file > $content ; set count = { len -e $content } - $n
stex -e ("["+makestr(int($count))) $content

The script is in biterscripting. To use, download biterscripting from http://www.biterscripting.com , save this script as C:\Scripts\last.txt, start biterscripting, enter the following command.

script last.txt file("c:\log09.txt") n(10)

The above will list last 10 lines from file c:\log09.txt. To list last 20 lines from the same file, use the following command.

script last.txt file("c:\log09.txt") n(20)

To list last 30 lines from a different file C:\folder1\somefile.log, use the following command.

script last.txt file("C:\folder1\somefile.log") n(30)

I wrote the script in a fairly generic way, so it can be used in various ways. Feel free to translate into another scripting/batch language.