I have two examples of very simple batch files:
Assigning a value to a variable:
@echo off
set FOO=1
echo FOO: %FOO%
pause
echo on
Which, as expected, results in:
FOO: 1
Press any key to continue . . .
However, if I place the same two lines inside an IF NOT DEFINED block:
@echo off
IF NOT DEFINED BAR (
set FOO=1
echo FOO: %FOO%
)
pause
echo on
This unexpectedly results in:
FOO:
Press any key to continue . . .
This shouldn't have anything to do with the IF, clearly the block is being executed. If I define BAR above the if, only the text from the PAUSE command is displayed, as expected.
What gives?
Follow up question:
Is there any way to enable delayed expansion without setlocal?
If I were to call this simple example batch file from inside another, the example sets FOO, but only LOCALLY.
For example:
testcaller.bat
@call test.bat
@echo FOO: %FOO%
@pause
test.bat
@setlocal EnableDelayedExpansion
@IF NOT DEFINED BAR (
@set FOO=1
@echo FOO: !FOO!
)
This displays:
FOO: 1
FOO:
Press any key to continue . . .
In this case, it appears that I have to enable delayed expansion in the CALLER, which may be a hassle.
Best Answer
Environment variables in batch files are expanded when a line is parsed. In the case of blocks delimited by parentheses (as your
if defined
) the whole block counts as a "line" or command.This means that all occurrences of %FOO% are replaces by their values before the block is run. In your case with nothing, as the variable doesn't have a value yet.
To solve this you can enable delayed expansion:
Delayed expansion causes variables delimited by exclamation marks (
!
) to be evaluated on execution instead of parsing which will ensure the correct behavior in your case:help set
details this too: