One of the most basic batch-file commands is Set—a circa-1982 command that displays, sets, or removes environment variables. Set has only gotten better with age, and in a way that most Set users are completely unaware of. So, this month, I'd like to offer some help to all of you batch-file writers with a new look at Set—specifically, its abilities to generate random numbers and perform arithmetic.

A Little Background
Environment variables store installation-specific information such as what a machine's name is (i.e., computername), whether the system is a 32-bit or 64-bit OS (i.e., processor_architecture), and where the OS should look for executable programs (i.e., path). Environment variables tend to fall into three categories: those the OS depends upon (e.g., the three I just cited), those that third-party applications use (e.g., I have QuickTime on my system, and it creates an environment variable named QTJAVA), and those that Windows' batch files use.

No matter how simple a programming language is—and Windows' batch language is among the simplest—that language needs a place for programmers to tuck away in-process data. Environment variables fill that role. However, a tool is necessary to get data into environment variables so that they're useful, and that tool is the Set command.

I know what you're thinking. Everyone understands the Set command! Come on! But do you really? Did you know that it can do arithmetic, or that it can perform substring operations on values in existing environment variables? Did you know that it can solicit input, or that it can generate random numbers? It can do all of those things—and more—but for now we'll focus on two of those capabilities, which reveal a couple interesting Set options.

Generate Random Numbers
Consider the simple batch file called guessnumber.cmd that Listing 1 shows. Copy this text to Notepad, save it to some folder on your path, and give the file the name guessnumber.cmd. Now, open a command prompt, type guessnumber, press Enter, and follow the prompts. It's a simple guessing game in which the batch file picks a random number, prompts you for a guess, then tells you that your guess is correct, too high, or too low—and if you haven't nailed it yet, it offers you another chance. (You should be able to guess the number in 16 or fewer guesses.) It's not the most amazing game in history, but it does run on Windows Server 2008 Server Core.

Consider this line, which picks the random number to guess:

set gamevalue=%random%

The key piece of this code is %random%, a function (built into Windows' command processor since Windows 2000 Server) that generates a random number between 0 and 32,767.

Once it generates the random number, the game needs to be able to repetitively ask the user for guesses. Prior to Win2K, batch files didn't offer a useful way to solicit input (as anyone who's ever wrestled with the Choice command knows). Ever since Win2K, though, Set has had a useful input capability via its /p option, as you see in this statement:

set /p latestguess=What do you think it is?

This command looks like

set /p environmentvariablename=\[prompttext\]

You can see that the prompt is, "What do you think it is?" Note the space after the question mark; it makes for nicer formatting. Whatever you type goes into an environment variable named latestguess.

Perform Arithmetic
I mentioned before that, given a range of values (32,768 possible integers), anyone should be able to guess any value within 16 tries. Let's modify that game, restricting the user to no more than 16 tries. We'll need a bit of arithmetic to keep track of how many guesses he or she has made, and you can see the result in Listing 2 in a revised version of guessnumber. A quick look at the guessnumber2.cmd code—which I've written to be short rather than elegant (hey, I'm no rock-star developer) —shows that the two batch files are different only in a few lines that introduce a new environment variable named guessesleft. I introduce that variable in a statement that anyone who's worked with any Microsoft OS since DOS 2.0 will recognize:

set guessesleft=16

Set's new arithmetic abilities appear in this statement:

set /a guessesleft=%guessesleft%-1

The trick is the /a option, which lets you do not only addition, subtraction, multiplication, division, and modulo computations, but also a few bitwise logical operations.

I hope I've given you a couple reasons to revisit an old and trusted—but perhaps underutilized—friend in Set. Join me next month for a look at an enhanced version of Set called Setx! Listing 1: Guessnumber.cmd

 echo off
set gamevalue=%random%
echo I'm thinking of a number between 0 and 32767.
:looptop
set /p latestguess=What do you think it is?
set guessright=false
if /i %latestguess% equ %gamevalue% echo You got it! & set guessright=true
if /i %latestguess% lss %gamevalue% echo Too small.
if /i %latestguess% gtr %gamevalue% echo Too large.
if NOT %guessright%<h1><a name="true_goto_looptop_pre_Listing_2_Guessnumber2_cmd_br_br_pre_class_code_style_margin_0in_0in_0pt_echo_off_set_guessesleft_16_set_gamevalue_random_echo_I_m_thinking_of_a_number_between_0_and_32767_echo_gamevalue_looptop_set_p_latestguess_What_s_your_guess_only_guessesleft_left_set_guessright_false_set_a_guessesleft_guessesleft_1_if_i_latestguess_equ_gamevalue_echo_You_got_it_amp_set_guessright_true_if_i_latestguess_lss_gamevalue_echo_Too_small_if_i_latestguess_gtr_gamevalue_echo_Too_large_if_i_guessesleft_leq_0_goto_byebye_if_NOT_guessright_">true goto looptop
</a></h1>

Listing 2: Guessnumber2.cmd

echo off
set guessesleft=16
set gamevalue=%random%
echo I'm thinking of a number between 0 and 32767.
echo %gamevalue%
:looptop
set /p latestguess=What's your guess (only %guessesleft% left)?
set guessright=false
set /a guessesleft=%guessesleft%-1

if /i %latestguess% equ %gamevalue% echo You got it! & set guessright=true
if /i %latestguess% lss %gamevalue% echo Too small.
if /i %latestguess% gtr %gamevalue% echo Too large.
if /i %guessesleft% leq 0 goto byebye
if NOT %guessright%true goto looptop
:byebye
if NOT %guessright%==true echo Sorry ... you used up all your turns. The number was %gamevalue%.