Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows Batch file to echo a specific line number

So for the second part of my current dilemma, I have a list of folders in c:\file_list.txt. I need to be able to extract them (well, echo them with some mods) based on the line number because this batch script is being called by an iterative macro process. I'm passing the line number as a parameter.

@echo off
setlocal enabledelayedexpansion
set /a counter=0
set /a %%a = ""
for /f "usebackq delims=" %%a in (c:\file_list.txt) do (
   if "!counter!"=="%1" goto :printme & set /a counter+=1
)
:printme
echo %%a

which gives me an output of %a. Doh! So, I've tried echoing !a! (result: ECHO is off.); I've tried echoing %a (result: a)

I figured the easy thing to do would be to modify the head.bat code found here: Windows batch command(s) to read first line from text file
except rather than echoing every line - I'd just echo the last line found. Not as simple as one might think. I've noticed that my counter is staying at zero for some reason; I'm wondering if the set /a counter+=1 is doing what I think it's doing.

like image 454
Lee Avatar asked Apr 23 '10 20:04

Lee


2 Answers

I know this is an old question, but here is some additional info for anyone with a similar issue...

Lee, your reasoning on why "%%a" isn't working outside the for loop is correct. The %a-z and %A-Z variables (%%a-z inside a batch file) are a construct of the for loop, and do not exist outside of it.

I would like to recommend an alternative solution to this problem that matches the correct line numbers (no empty lines skipped) and does not require delayed expansion, counters, or a goto statement. Take a look at the following code:

@echo off
for /f "tokens=1* delims=:" %%a in ('findstr /n .* "c:\file_list.txt"') do if "%%a"=="%1" set line=%%b
echo.%line%

Here is what led me to the above changes. Let's say you had the following file contents:

Some text on line 1
Blah blah blah
More text

The first thing I did was change (c:\file_list.txt).to ('findstr /n .* "c:\file_list.txt"').

  • 'findstr /n .* "PATH\FILENAME"' reads the file and adds a line number ('/n') to every line ('.*' is a regular expression matching "0 or more" of any character). Since every line will now have a line number at the beginning (even the empty ones), no lines will be skipped by the for loop.

Each line will now look like this inside the for loop:

1:Some text on line 1
2:Blah blah blah
3:More text

Next, we use "tokens=1* delims=:" to break up the line number and the content.

  • 'tokens=1*' sets the first token (stored in %%a) to everything before the delimiter, and the second token (stored in %%b) to everything after it.
  • 'delims=:' sets ":" as the delimiter character used to break up the string.

Now as we loop through the file, %%a will return the current line number and %%b will return the content of that line.

All that's left is to compare the %1 parameter to %%a (instead of a counter variable) and use %%b to store the current line content: if "%%a" =="%1" set line=%%b.

An added bonus is that 'enabledelayedexpansion' is no longer necessary, since the above code eliminates reading a counter variable in the middle of a for loop.

Edit: changed 'echo %line%' to 'echo.%line%'. This will correctly display blank lines now, instead of "ECHO is off.". Changed 'type c:\file_list.txt ^| findstr /n .*' to 'findstr /n .* "c:\file_list.txt"', since the findstr command can already read files directly.

Jeb, I think I've solved all the special character issues. Give this a shot:

for /f "tokens=*" %%a in ('findstr /n .* "c:\file_list.txt"') do (
  set "FullLine=%%a"
  for /f "tokens=1* delims=:" %%b in ("%%a") do (
    setlocal enabledelayedexpansion
    set "LineData=!FullLine:*:=!"
    if "%%b" equ "%1" echo(!LineData!
    endlocal
  )
)
like image 85
Seth McCauley Avatar answered Sep 29 '22 22:09

Seth McCauley


Bah, it ate my formatting.

@echo off

setlocal enabledelayedexpansion

set /a counter=0
set %%a = ""

for /f "usebackq delims=" %%a in (c:\file_list.txt) do (if "!counter!"=="%1" goto :printme & set /a counter+=1)

:printme

echo %%a%
like image 41
Lee Avatar answered Sep 29 '22 21:09

Lee