<http://www.netikka.net/tsneti/info/tscmd069.htm>
Copyright © 2003-2012 by Prof. Timo Salmi  
Last modified Tue 28-Aug-2012 03:39:16

 
Assorted NT/2000/XP/.. CMD.EXE Script Tricks
From the html version of the tscmd.zip 1cmdfaq.txt file
To the Description and the Index
 

This page is edited from the 1cmdfaq.txt faq-file contained in my tscmd.zip command line interface (CLI) collection. That zipped file has much additional material, including a number of detached .cmd script files. It is recommended that you also get the zipped version as a companion.

Please see "The Description and the Index page" for the conditions of usage and other such information.



69} How do I get the first, or the last, 400 lines of a file?

A question of "head" and "tail" in UNIX terminology. This is a task that is well suited for SED or for an actual head or tail UNIX port.


The first part of this page concerns "head"

The easiest solution is to use SED
  @echo off
  sed -n 1,400p myfile.txt

Assume the following LFN-type test file: "My test file.txt"
line 1
line 2 &()[]{}^=;!'+,`~
line 3 <>
line 4

line 6 Line 5 is empty!
line 7
line 8 &()[]{}^=;!'+,`~
line 9

  @echo off & setlocal enableextensions
  set myfile_=My test file.txt
  for /f "tokens=* delims=" %%f in ("%myfile_%") do (
    set myfile_=%%~sf)
  sed -n 1,6p "%myfile_%"
  endlocal & goto :EOF

The output will be
  C:\_D\TEST>cmdfaq
  line 1
  line 2 &()[]{}^=;!'+,`~
  line 3 <>
  line 4

  line 6 Line 5 is empty!

The renaming to a SFN-format is needed when the SED version usually assumed in this FAQ is used. However, if the GnuWin32 SED (let us call it here UNXSED for distinction) is used, then the LFN/SFN file name conversion is not needed. Furthermore, the said collection contains head and tail UNIX ports, which also could be used in this item.

  @echo off & setlocal enableextensions
  unxsed 6q "My test file.txt"
  endlocal & goto :EOF

The output will be
  C:\_D\TEST>cmdfaq
  line 1
  line 2 &()[]{}^=;!'+,`~
  line 3 <>
  line 4

  line 6 Line 5 is empty!

With GnuWin32 G(nu)AWK from the solution is
  @echo off & setlocal enableextensions
  set myfile_=My test file.txt
  unxgawk "NR<=6 {printf \"%%s\n\",$0}" "%myfile_%"
  endlocal & goto :EOF

A Visual Basic Script (VBScript) aided command line script version of "head"
  @echo off & setlocal enableextensions
  ::
  :: Build a Visual Basic Script
  set skip=
  set vbs_=%temp%\vhead.vbs
  for /f "tokens=*" %%f in ("%vbs_%") do set vbs_=%%~sf
  findstr "'%skip%VBS" "%~f0" > %vbs_%
  ::
  :: Run the script with Microsoft Windows Script Host Version 5.6
  cscript //nologo %vbs_% 6 < "My test file.txt"
  ::
  :: Clean up
  for %%f in (%vbs_%) do del %%f
  endlocal & goto :EOF
  '
  '.......................................................
  'The Visual Basic Script for "head"
  '
  StopAfter=WScript.Arguments.Unnamed(0) 'VBS
  i = 0 'VBS
  Do While Not WScript.StdIn.AtEndOfStream 'VBS
    str = WScript.StdIn.ReadLine 'VBS
    i = i + 1 'VBS
    If i <= CInt(StopAfter) Then 'VBS
      WScript.StdOut.WriteLine str 'VBS
    End If 'VBS
  Loop 'VBS

The output will again be
  C:\_D\TEST>cmdfaq
  line 1
  line 2 &()[]{}^=;!'+,`~
  line 3 <>
  line 4

  line 6 Line 5 is empty!

Also pure CMD script solutions can be attempted, but they have limitations with the empty lines and some of the special characters. Thus for genric purposes these solutions are not recommended.

Getting just the first line
  @echo off & setlocal enableextensions
  set /p first_=<"My test file.txt"
  echo %first_%
  endlocal & goto :EOF

The output will be
  C:\_D\TEST>cmdfaq
  line 1
or
  @echo off & setlocal enableextensions
  for /f "tokens=* delims=" %%a in (
    'type "My test file.txt"') do (
      set FirstLine=%%a& goto _ExitForLoop)
  :_ExitForLoop
  echo FirstLine=%FirstLine%
  endlocal & goto :EOF

The output will be
  C:\_D\TEST>cmdfaq
  FirstLine=line 1

For multiple lines:
  @echo off & setlocal enableextensions disabledelayedexpansion
  set LineCount=0
  for /f "tokens=* delims=" %%r in (
    'type "My test file.txt"') do call :EchoLine "%%r"
  endlocal & goto :EOF
  ::
  :EchoLine
  set /a LineCount+=1
  if %LineCount% GTR 6 goto :EOF
  echo "%~1"
  endlocal & goto :EOF

The output will be
  C:\_D\TEST>cmdfaq
  "line 1"
  "line 2 &()[]{}^^=;!'+,`~"
  "line 3 <>"
  "line 4"
  "line 6 Line 5 is empty!"
  "line 7"
which probably is not quite what we want from a useful solution.


The second part of this page concerns "tail"

From a sed one-liner's collection by Eric Pement
  sed -e :a -e "$q;N;401,$D;ba" myfile.txt

To get the last six lines (tail -6) of our test file
  @echo off & setlocal enableextensions
  unxsed -e :a -e "$q;N;7,$D;ba" "My test file.txt"
  endlocal & goto :EOF

  The output will be
  C:\_D\TEST>cmdfaq
  line 4

  line 6 Line 5 is empty!
  line 7
  line 8 &()[]{}^=;!'+,`~
  line 9

Visual Basic Script (VBScript) aided command line script version of "tail"
  @echo off & setlocal enableextensions
  ::
  :: Build a Visual Basic Script
  set skip=
  set vbs_=%temp%\vtail.vbs
  for /f "tokens=*" %%f in ("%vbs_%") do set vbs_=%%~sf
  findstr "'%skip%VBS" "%~f0" > %vbs_%
  ::
  :: Run the script with Microsoft Windows Script Host Version 5.6
  cscript //nologo %vbs_% "My test file.txt" 6
  ::
  :: Clean up
  for %%f in (%vbs_%) do del %%f
  endlocal & goto :EOF
  '
  '.......................................................
  'The Visual Basic Script
  '
  ' Define some constants
  Const ForReading = 1, ForWriting = 2, ForAppending = 8 'VBS
  Dim fileName, FSO, f, i, n, nArg, s 'VBS
  '
  ' Check the right usage
  nArg = WScript.Arguments.Count 'VBS
  If (nArg = 0) Or (nArg > 2) Then 'VBS
    s = "Usage: cscript //nologo " 'VBS
    s = s & WScript.ScriptName 'VBS
    s = s & " fileName [NumberOfLinesFromEnd]" 'VBS
    WScript.Echo s 'VBS
    WScript.Quit 'VBS
  End If 'VBS
  '
  ' Get the arguments: fileName and tailLines
  fileName=WScript.Arguments.Unnamed(0) 'VBS
  If WScript.Arguments.Count > 1 Then 'VBS
    tailLines = CLng(WScript.Arguments.Unnamed(1)) 'VBS
  Else 'VBS
    tailLines = 10 'VBS
  End If 'VBS
  '
  ' Check that the file exists
  Set FSO=CreateObject("Scripting.FileSystemObject") 'VBS
  if not FSO.FileExists(fileName) Then 'VBS
    WScript.Echo "File " & fileName & " Not Found" 'VBS
    WScript.Quit 'VBS
  End If 'VBS
  '
  ' Calculate the number of lines
  Set f = FSO.OpenTextFile(fileName, ForReading, True) 'VBS
  n = 0 'VBS
  Do While Not f.AtEndOfStream 'VBS
    n = n + 1 'VBS
    s = f.ReadLine 'VBS
  Loop 'VBS
  '
  ' Output the tail part of the file
  Set f = FSO.OpenTextFile(fileName, ForReading, True) 'VBS
  i = 0 'VBS
  Do While Not f.AtEndOfStream 'VBS
    i = i + 1 'VBS
    s = f.ReadLine 'VBS
    If i > n - tailLines Then WScript.Echo s 'VBS
  Loop 'VBS

The output will be
  C:\_D\TEST>cmdfaq
  line 4

  line 6 Line 5 is empty!
  line 7
  line 8 &()[]{}^=;!'+,`~
  line 9

However, if we are guaranteed an input file with no blank lines and no poison chracters, then there is a pure CMD script solution for getting the tail of the file. See Item #181 for the code.

What about the other way round? Present all but the first two lines of a text file:
  @echo off & setlocal enableextensions
  more /e +2 "My test file.txt" > "%temp%\tmp$$$.prn"
  type "%temp%\tmp$$$.prn"
  if exist "%temp%\tmp$$$.prn" del "%temp%\tmp$$$.prn"
  endlocal & goto :EOF

The output will be
  C:\_D\TEST>cmdfaq
  line 3 <>
  line 4

  line 6 Line 5 is empty!
  line 7
  line 8 &()[]{}^=;!'+,`~
  line 9
or with sed
  @echo off & setlocal enableextensions
  unxsed -n 3,$p "My test file.txt"
  endlocal & goto :EOF

Getting all but the last line of a file and getting all but (e.g.) the last three lines of a file are covered in item #23.

References/Comments: (If a Google message link fails try the links within the brackets.)
  Google Groups May 8 2005, 10:39 am [M]
  Google Groups May 11 2005, 7:45 pm [M]
  Google Groups 01 Jul 2008 05:42:47 +1000 [M]