<http://www.netikka.net/tsneti/info/tscmd049.htm>
Copyright © 2003- by Prof. Timo Salmi  
Last modified Sat 28-Jan-2017 17:24:13


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.



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

Assume e.g. 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

The shortest solution is using a SED one-liner (skips, however, the empty lines with the old sed version):
  @echo off & setlocal enableextensions
  type "My test file.txt"|sed -n "1!G;h;$p"
  endlocal & goto :EOF

C:\_D\TEST>cmdfaq
line 9
line 8 &()[]{}^=;!'+,`~
line 7
line 6 Line 5 is empty!
line 4
line 3 <>
line 2 &()[]{}^=;!'+,`~
line 1

  @echo off & setlocal enableextensions
  unxsed "1!G;h;$!d" "My test file.txt"
  endlocal & goto :EOF

C:\_D\TEST>cmdfaq
line 9
line 8 &()[]{}^=;!'+,`~
line 7
line 6 Line 5 is empty!

line 4
line 3 <>
line 2 &()[]{}^=;!'+,`~
line 1

There are other, longer solutions, which are included for demonstration. First with G(nu)AWK.
  @echo off & setlocal enableextensions
  set awk_=%temp%\tmp$$$.awk
  set tmf_=%temp%\tmp$$$.txt
  >  "%awk_%" echo {p=length(NR)
  >> "%awk_%" echo lead="000"
  >> "%awk_%" echo lead=substr(lead,1,4-p)
  >> "%awk_%" echo printf"%%s%%s£%%s\n",lead,NR,$0}
  ::
  type "My test file.txt"|gawk -f "%awk_%">"%tmf_%"
  type "%tmf_%"|sort /r|gawk -F£ '{printf "%%s\n",$2}'
  ::
  for %%f in ("%tmf_%" "%awk_%") do if exist %%f del %%f
  endlocal & goto :EOF

The ouput is
C:\_D\TEST>cmdfaq
line 9
line 8 &()[]{}^=;!'+,`~
line 7
line 6 Line 5 is empty!

line 4
line 3 <>
line 2 &()[]{}^=;!'+,`~
line 1

Another version. It does not need the £ trick.
  @echo off & setlocal enableextensions
  set myfile_=My test file.txt
  for /f "tokens=* delims=" %%f in ("%myfile_%") do (
    set myfile_=%%~sf)
  set tmp1_=%temp%\tmp$$$.txt
  set tmp2_=%temp%\tmp$$2.txt
  gawk '{printf"%%4s %%s\n",NR,$0}' "%myfile_%" > "%tmp1_%"
  <"%tmp1_%" sed -e"s/^   /000/" -e"s/^  /00/" -e"s/^ /0/">"%tmp2_%"
  <"%tmp2_%" sort /r | gawk '{print substr($0,6)}'
  for %%f in ("%tmp1_%" "%tmp2_%") do if exist %%f del %%f
  endlocal & goto :EOF

Also
  @echo off & setlocal enableextensions
  type "My test file.txt"|gawk "{Array[NR]=$0}END{for(x=NR;x!=0;x--)print Array[x]}"
  endlocal & goto :EOF

There is a possibility of a pure script solution. This solution benefits from a discussion in the news:alt.msdos.batch.nt as per the earlier item #23. This also introduced the use of FOR /L for the first time in the original FAQ collection.
  @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
  ::
  :: Loop through the lines of the file from the last line to the first

  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
However, this solution is not generic! It fails if the file contains "poison characters" and/or empty lines. (C.f. the first example file.)

A VBS-aided script can be used for a fast and generic, but memory-intensive solution
  @echo off & setlocal enableextensions
  ::
  set myfile_=C:\_D\TEST\My test file.txt
  ::
  :: Build a Visual Basic Script

  set skip=
  set vbs_=%temp%\tmp$$$.vbs
  findstr "'%skip%VBS" "%~f0" > "%vbs_%"
  ::
  :: Run it with Microsoft Windows Script Host Version 5.6

  <"%myfile_%" cscript //nologo "%vbs_%"
  ::
  :: Clean up

  for %%f in ("%vbs_%") do if exist %%f del %%f
  endlocal & goto :EOF
  '
  ' The Visual Basic Script

  Dim LineArray(1000) 'VBS, increase the dimension if necessary
  ' Read the file from StdIn into an array
  n = 0 'VBS
  Do While Not WScript.StdIn.AtEndOfStream 'VBS
    n = n + 1 'VBS
    LineArray(n) = WScript.StdIn.ReadLine 'VBS
  Loop 'VBS
  ' Write out the array, reversed
  For i = n To 1 Step -1 'VBS
    WScript.Echo LineArray(i) 'VBS
  Next 'VBS

References/Comments:
  Feb 4 Matthias Tacke Suggestion for Tscmd 049 in tspost28.zip Information email + postings, from 19-Sep-00 to ...