2

I need to set some variables based on an argument for a windows batch script.

@echo off       
if [%1]==[] (
    echo "Usage: xxx <AAA|ZZZ>"
) else (
    if [%1]==[AAA] (
        SET SOURCE_DIR=c:\dirA
    ) else if [%1]==[ZZZ] (
        SET SOURCE_DIR=c:\dirZ
    ) 
    echo Source dir is: %SOURCE_DIR%
)

When I call the above script with parameter AAA, I get the output

Source dir is: c:\dirA

after the second call. From then onwards when I alternate between AAA and ZZZ, I get this pattern:

C:\stageing-area>test.bat AAA
Source dir is: c:\dirZ
C:\stageing-area>test.bat ZZZ
Source dir is: c:\dirA
C:\stageing-area>test.bat AAA
Source dir is: c:\dirZ
C:\stageing-area>test.bat ZZZ
Source dir is: c:\dirA

So it looks like I am manipulating a global variable that is available even after the script has finished. This alone doesn't bother me but that the new setting is only available after the script terminates is a problem, as the rest of my script depends on it (obviously).

What is the correct use of local variables in this context? How to explain the weird behaviour of the above "defered state setting"?

Thanks!

raoulsson
  • 4,763
  • 10
  • 34
  • 29

2 Answers2

2

Variables in a batch file are by default expanded at the beginning of script execution; you need to use delayed expansion, which is available with the "!" delimiter:

echo Source dir is: !SOURCE_DIR!

This only works if delayed expansion is enabled for the command interpreter, which by default is not; so you need to enable it when starting the interpreter, using CMD.EXE /V.

You can also enable it using this statement in your batch file:

setlocal ENABLEDELAYEDEXPANSION

More info here.

Massimo
  • 70,200
  • 57
  • 200
  • 323
1

I might have handled it a little simpler...

@ECHO OFF       
SET SOURCE_DIR=
IF /I [%1]==[AAA] SET SOURCE_DIR=c:\dirA
IF /I [%1]==[ZZZ] SET SOURCE_DIR=c:\dirZ
IF [%SOURCE_DIR]==[] (
    ECHO "Usage: xxx <AAA|ZZZ>"
    EXIT 1
) 
ECHO Source dir is: %SOURCE_DIR%

I have to admit, I am a bit baffled as to why this works when the example in the question does not. My best guess is that it is a scoping problem. Because in the example, the variable SOURCE_DIR was set within the parens, its value in the root scope it remains unchanged. My script changes SOURCE_DIR in the root scope.

As to why the Delayed Expansion trick causes it to pickup the change that was made a scope level deeper, it seems the expansion happens at the beginning of each scope change. So by delaying, you are basically forcing it to re-expand after returning to the root scope.

Nathan Hartley
  • 1,660
  • 5
  • 26
  • 40