views:

2042

answers:

3

Hi I'm tryin' to find a script that will let me display "linenumber# and linenumber# as well as lines#-#" from a text file in a batch file? I found this script here on this site..

@echo off
setlocal enabledelayedexpansion
if [%1] == [] goto usage
if [%2] == [] goto usage

SET /a counter=0

for /f "usebackq delims=" %%a in (%2) do (
if "!counter!"=="%1" goto exit
echo %%a
set /a counter+=1
)

goto exit

:usage
echo Usage: head.bat COUNT FILENAME

:exit

And it works great :) But it grabs the number of lines from the top of the text file. I want to be able to display certain lines in the text file, as well as a range if possible..

EG: I have a text file with 30 lines, and I want to display lines 1-4; 7-11; 13; 17-20; 22; 26 & 29

A: 

Seems to work:

@ECHO OFF
REM Show usage and quit if no file name was given
IF [%1]==[] GOTO USAGE
REM Show entire file if no range was given
IF [%2]==[] TYPE %1 & GOTO :EOF

SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

SET FILENAME=%1
SET LASTLINE=0

REM Build the array of lines to display
SHIFT
:RANGEREADLOOP
CALL :BUILDARRAY %1
SHIFT
IF NOT [%1]==[] GOTO RANGEREADLOOP

REM Loop through the file and keep track of the lines to display
SET CURRENTLINE=0
SET INDEX=1
FOR /F "delims=" %%l in (%FILENAME%) DO (
    SET LINE=%%l
    CALL :PRINTLINE
)

GOTO :EOF

REM Adds the lines from the specified range to the array of lines to display
:BUILDARRAY
    REM Find out whether we have a single line or a range
    SET TEST=%1
    SET /A TEST1=%TEST%
    SET /A TEST2=%TEST:-=%
    IF %TEST1%==%TEST2% (
        REM Single line
        SET /A LASTLINE+=1
        SET LINES[!LASTLINE!]=%1
    ) ELSE (
        REM Range
        FOR /F "tokens=1,2 delims=-" %%x IN ("%1") DO (SET RANGESTART=%%x&SET RANGEEND=%%y)
        REM Some sanity checking
        IF !RANGESTART! GTR !RANGEEND! (
            ECHO.Problem with range !RANGESTART!-!RANGEEND!:
            ECHO.  Ranges must have a start value smaller than the end value.
            EXIT /B 1
        ) ELSE (
            FOR /L %%i IN (!RANGESTART!,1,!RANGEEND!) DO (
                SET /A LASTLINE+=1
                SET LINES[!LASTLINE!]=%%i
            )
        )
    )
GOTO :EOF

REM Prints the specified line if the current line should be printed
:PRINTLINE
    SET /A CURRENTLINE+=1
    IF %CURRENTLINE%==!LINES[%INDEX%]! (
        REM We have a line to print, so do this
        ECHO !LINE!
        SET /A INDEX+=1
    )
GOTO :EOF

REM Prints usage and exits the batch file
:USAGE
    ECHO.%~n0 - Displays selected lines from a text file.
    ECHO.
    ECHO.Usage:
    ECHO.  %~n0 ^<filename^> ^<range^> ...
    ECHO.
    ECHO.  ^<filename^> - the text file from which to read
    ECHO.  ^<range^>    - the line range(s) to display.
    ECHO.
    ECHO.Example:
    ECHO.  %~n0 foo.txt 1-4 13 15 18-20
    ECHO.
    ECHO.  will display the first four lines from the file "foo.txt",
    ECHO.  the 13th and 15th as well as the lines 18 to 20.
    ECHO.
    ECHO.Line ranges are separated by comma, semicolon or space. If no range is given,
    ECHO.the entire file is displayed.
    EXIT /B 1
GOTO :EOF

The whole script could use some better error checking, examples of what not to do or where error checking is a bit wonky:

  • dl foo.txt 1-2-4 (prints lines 1-2 but no error message)
  • dl foo.txt -1 (error message that the range 1- isn't correct)

Other limitations:

  • Ranges must be sorted. With the current implementation there is no way to do something like dl foo.txt 7-8,1-2.
  • No line may be selected twice. Something like dl foo.txt 1,2,2-8,11-15 will stop after the second line.
  • No support for UNIX-style line endings (U+000A)

EDIT: Fixed an issue with files that contain parentheses.

Joey
+1  A: 

Here's a simple modification of the sample batch file above. Copy the code below to file and name it "LineDisplay.bat" - it takes the FirstLineNumber and LastLineNumber as parameters. Example: LineDisplay test.txt 12 30 (to read lines 12-30)

@echo off
setlocal enabledelayedexpansion
if [%1] == [] goto usage
if [%2] == [] goto usage
if [%3] == [] goto usage

set /a FirstLineNumber = %2
set /a LastLineNumber = %3

echo Reading from Line !FirstLineNumber! to !LastLineNumber!


SET /a counter=1

for /f "usebackq delims=" %%a in (%1) do (
    if !counter! GTR !LastLineNumber! goto exit
    if !counter! GEQ !FirstLineNumber! echo !counter! %%a
    set /a counter+=1
)

goto exit

:usage
echo Usage: LineDisplay.bat FILENAME FirstLineNumber LastLineNumber

:exit

Here's a line to a nice tutorial on creating batch files http://vtatila.kapsi.fi/batch_tutorial.html

Jose Basilio
A: 

Cheers Johannes! Awesome work. After the last line I get a ": was expected at this time" I've learned alot from this, and from the site that Jose posted to. But I can't seem to work out where the line number itself is displayed, because I don't want the line number to be displayed, just echo whatever is on the line itself :) Cheers for your help.

I fixed that issue. I just didn't have files with parentheses in them for testing that's why I didn't run into it. By the way, this should have been a comment and not an answer, and you can accept answers you consider correct and helpful, as well as upvote them.
Joey
also I removed the line number from the output now. It was in the only echo statement in the PRINTLINE subroutine ... pretty easy to find :D
Joey