user1664025
user1664025

Reputation: 11

Call a variable based on a second variable in a batch file

The process of the program i am trying to right is to take a text file with a number of words in, and set each one to a variable, then echo a random variable form the list set. So far my code looks as follows:

@Echo Off
Set _InputFile=config.txt
//Sets the Input file
For /F "tokens=1,2* delims=:" %%A IN (%_InputFile%) DO Set _Data%%A=%%B
//Sets each Word to a vairable from _data1 to _datax
set n=(random number code)
//Set's N to be a rational random number depending on the variables available
Echo _data%%n
//This is where i get stuck, i need to be able to echo _data(whatever number n is)
pause>nul

So basically my main problem is getting the file to echo a random variable based on the value of another variable. An alternate method would also be appreciated if it is better/more appropriate than what i am trying.

Secondly (a smaller issue) is there any way to determine the number of words (or lines as it will be the same thing) in config.txt and then assign that number to a variable?

Upvotes: 1

Views: 356

Answers (2)

James K
James K

Reputation: 4055

To answer your second question first, there are several methods for getting the number of lines in a file quickly.

Using the FIND.EXE method:

for /f %%x in ('type %FileName% ^| find /v /c ""') do set Lines=%%x

The advantage of using find.exe is that find zipps though any text file like mad, and that it will count even blank lines.

Using the for method:

for /f %%x in (%FileName%) do set /a count=count+1

The drawback for the second method is that for loops automatically skip blank lines. The advantage to this method is that the file need only be accessed once.

Since we are going to read in each line of the file and manipulate it, it will be more efficient to count each line when you read it in.


Before we go on I should point out that // is not a comment mark in Batch and will cause errors. Either use REM, the REMark command, or a pair of double-colons :: to denote comments.

Notice the setlocal enabledelayedexpansion and endlocal lines. SETLOCAL makes all variables temporary so exist only during the execution of the script, eliminating the need to clear every variable at the end of the script. enableDelayedExpansion enables the use of ! notation, allowing variables to be accessed like so: !Variable!. Lastly endLocal specifies WHERE in the script all the temporary variables die or revert to their pre-setlocal values. If you eliminate the endLocal line there will be an implied endlocal when the batch file ends.

@Echo Off
setlocal enabledelayedexpansion
Set _InputFile=CONFIG.TXT
set count=

:: Sets each line to a vairable from _data1 to _data##
For /F "tokens=1* delims=:" %%A IN (%_InputFile%) DO (
    set /a count=!count!+1
    Set "_Data!count!=%%A"
)

:: Create a random number between 1 and %count% using the MOD function in 'set /a'
:: Equivalent to: SET /A n = aRandomNumber - ( theSameRandomNumber / %Count% ) + 1
:: See http://en.wikipedia.org/wiki/Mod_function
set /a n=%random% %% %count% +1

:: Echo # of lines, a random # from 1 to %count%, and a random line from the file:
echo.
echo =================================================
echo File is %count% lines deep
echo Random #: %n%

:: Print a random line of data
:: We are taking advantage of Delayed Expansion and ! notation:
Echo Random Line: "!_data%n%!"
echo.

:: Use SET to echo every line of data read in
echo Whole Set of _data[#] data:
set _data
echo.

endlocal

One thing to keep in mind is that CMD.EXE brings some of the limitations that were inherent in old MS-DOS. In this case there are two important limitations:

1) There is a severe limits on the amount of memory available for use.
2) Setting Environmental Variables uses a lot of the memory available to a CMD.EXE session.

What this means for you is that you will be limited to creating about 100 _data variables, so no data past that point can be saved to a variable.

In older versions of Windows you could create a .PIF file (at the command line type copy nul BatchName.PIF then right-clicking it in Windows Explorer and selecting Properties) for your batch file and change the amount of memory that would be allocated for it when it ran. I think you could even do that under XP, but I know that in Windows 7 you cannot. Though it may be possible to download an existing .PIF file and connecting it to your batch file, but I don't know.

Upvotes: 1

dbenham
dbenham

Reputation: 130889

1) Use CALL to get 2 expansion phases - one before the call, and one after. This is slow, and visually confusing. Also it is the least reliable because many characters have the ability to corrupt the results.

call echo %%_Data%n%%%

2) Delayed Expansion - Much faster, easier to follow method that always works. However, delayed expansion will corrupt FOR variable expansion if the FOR variable contains the ! character. Delayed expansion must be enabled before it can be used.

setlocal enableDelayedExpansion
::Above line must be executed sometime before the following
echo !_Data%n%!

2a) If the n variable is being set within the same parenthesised block of code that is trying to echo the value, then %n% will not work. This problem often arises with FOR loops and IF statements. It fails because %n% is expanded when the entire block is parsed, before the value of n has been set. The trick is to transfer the value of !n! to a FOR variable.

setlocal enableDelayedExpansion
for .... (
  set n = ....
  for %%N in (!n!) do echo !_Data%%N!
)

Here is a convenient method to get a pseudo random number between 1 and x. It relies on the predefined dynamic variable: RANDOM.

set /a n=%random% %% x + 1

If computing the value in a loop, then you probably want delayed expansion so that you get a different number with each iteration.

set /a n=!random! %% x + 1

Upvotes: 3

Related Questions