Friday, July 13, 2007

Dynamic Variable Name

Sometimes I find myself missing the ability to use arrays in batch scripts. OK, a lot of times. So to get around that, I often have to resort to using variable names that start with the same string and end with numbers. Like VAR1, VAR2, etc.

Now I know that is lame but it gets the job done. But what if I want to create these variables dynamically? I mean, if I want to read a file, and assign each line in the file to a separate variable, I need to know how many lines there are in the file, otherwise I'm screwed. Right? Well, not quite.

What I find is, some people quite often missed the fact that you can use variable expansion as a name of a new variable in batch. I guess that's because it's rather counter intuitive from other programming languages.

Anyway, the following example reads a file, assign each line to a new variable name and prints the file back, line by line, in reverse order.

@echo off

setlocal enabledelayedexpansion

set COUNT=0

for /F "tokens=*" %%n in (foo.txt) do (

  set /A COUNT=!COUNT! + 1

  echo %%n

  set LINE!COUNT!=%%n

)

for /L %%c in (!COUNT!,-1,1) do (

  echo !LINE%%c!

)

First of all, you need to enable delayed expansion for this to work (see my earlier post about that). Then you want to treat everything on one line as one value, so you use the "tokens=*" option for the firs for loop.

In that first loop you maintain a count, and create a new variable named LINE!COUNT! in each iteration, and assign the whole line to that new variable. See how simple that was?

The second loop just iterates through the count backward using the for /L option, and print the variables in that reverse order. Now take a look at how I'm printing the line. I use !LINE%%c! which uses both the ! and the % to allow the proper expansion of the variable name.

You can also replace the second loop with some other thing like string replacement.

echo. & echo Replace all 'h' with 'y' & echo.

for /L %%c in (1,1,!COUNT!) do (

  set CURRLINE=!LINE%%c!

  set CURRLINE=!CURRLINE:h=y!

  echo !CURRLINE!

)

Voila! Quick and dirty poorman's implementation of UNIX tr command. Of course you don't need to even save the lines to their own separate variables to do that. You can just do the replacement as you read the lines, and print the line out all in the same loop iteration. But hey, that's why they're called examples.

No comments: