Home » Questions » Computers [ Ask a new question ]

Variables in batch file not being set when inside IF?

Variables in batch file not being set when inside IF?

I have two examples of very simple batch files:

Asked by: Guest | Views: 67
Total answers/comments: 3
Guest [Entry]

"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:

setlocal enabledelayedexpansion

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:

if not defined BAR (
set FOO=1
echo Foo: !FOO!
)

help set details this too:

Finally, support for delayed
environment variable expansion has
been added. This support is always
disabled by default, but may be
enabled/disabled via the /V command
line switch to CMD.EXE. See CMD /?

Delayed environment variable expansion
is useful for getting around the
limitations of the current expansion
which happens when a line of text is
read, not when it is executed. The
following example demonstrates the
problem with immediate variable
expansion:

set VAR=before
if ""%VAR%"" == ""before"" (
set VAR=after
if ""%VAR%"" == ""after"" @echo If you see this, it worked
)


would never display the message, since
the %VAR% in both IF statements is
substituted when the first IF
statement is read, since it logically
includes the body of the IF, which is
a compound statement. So the IF
inside the compound statement is
really comparing ""before"" with ""after""
which will never be equal. Similarly,
the following example will not work as
expected:

set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%


in that it will not build up a list of
files in the current directory, but
instead will just set the LIST
variable to the last file found.
Again, this is because the %LIST% is
expanded just once when the FOR
statement is read, and at that time
the LIST variable is empty. So the
actual FOR loop we are executing is:

for %i in (*) do set LIST= %i


which just keeps setting LIST to the
last file found.

Delayed environment variable expansion
allows you to use a different
character (the exclamation mark) to
expand environment variables at
execution time. If delayed variable
expansion is enabled, the above
examples could be written as follows
to work as intended:

set VAR=before
if ""%VAR%"" == ""before"" (
set VAR=after
if ""!VAR!"" == ""after"" @echo If you see this, it worked
)

set LIST=
for %i in (*) do set LIST=!LIST! %i
echo %LIST%"
Guest [Entry]

"If it isn't working that way, you likely have delayed environment variable expansion on. You can either turn it off with cmd /V:OFF or use exclamation marks inside your if:

@echo off
IF NOT DEFINED BAR (
set FOO=1
echo FOO: !FOO!
)
pause
echo on"
Guest [Entry]

"Sometimes, as I had in my case, when you need to be compatible with legacy systems like old NT4 servers where delayed expansion are not working or for some reason is not working you may need alternate solution.

In case you will use Delayd Expansion, also recommended that at least check in batch should be included:

IF NOT %Comspec%==!Comspec! ECHO Delayed Expansion is NOT enabled.

In case you just want more readable and simple approach, here are alternate solutions:

REM Option 2: use `call` inside block statement
IF NOT DEFINED BAR2 (
set FOO2=2
call echo FOO2: %%FOO2%%
)
echo FOO2: %FOO2%

which works like this:

>REM Option 2: use `call` inside block statement

>IF NOT DEFINED BAR2 (
set FOO2=2
call echo FOO2: %FOO2%
)
FOO2: 2

>echo FOO2: 2
FOO2: 2

and one more pure cmd solution:

REM Option 3: use `goto` logic blocks
IF DEFINED BAR3 goto endbar3
set FOO3=3
echo FOO3: %FOO3%
:endbar3
echo FOO3: %FOO3%

it works like this:

>REM Option 3: use `goto` logic blocks

>IF DEFINED BAR3 goto endbar3

>set FOO3=3

>echo FOO3: 3
FOO3: 3

>echo FOO3: 3
FOO3: 3

and this is full IF THEN ELSE syntax solution:

REM Full IF THEN ELSE solution
IF NOT DEFINED BAR4 goto elsebar4
REM this is TRUE condition, normal batch flow
set FOO4=6
echo FOO4: %FOO4%
goto endbar4
:elsebar4
set FOO4=4
echo FOO4: %FOO4%
set BAR4=4
:endbar4
echo FOO4: %FOO4%
echo BAR4: %BAR4%

it works like this:

>REM Full IF THEN ELSE solution

>IF NOT DEFINED BAR4 goto elsebar4

>set FOO4=4

>echo FOO4: 4
FOO4: 4

>set BAR4=4

>echo FOO4: 4
FOO4: 4

>echo BAR4: 4
BAR4: 4"