Windows Batch Variables Won't Set

WindowsBatch FileIf StatementCmdDelayedvariableexpansion

Windows Problem Overview


I think I ran into a bug in Window's batch scripting.

I cannot set variables that are in an expanded if statement.

Here is an isolated part of my script:

@echo off

set success=1
set Version=12345
set Target=Client
set Type=456
set dir=
set zip=

if "%Version%"=="" set success=0
if "%Type%"=="" set success=0

if 1==1 set test=42

if %success%==1 (
	set test2=57005
	if "%Target%"=="Client" (
		set dir=ModName v%Version%
		set zip=ModName v%Version% %Type%.zip
		echo Version: %Version%
		echo    Type: %Type%
		echo.
		echo  Target: %Target%
		echo     dir: %dir%
		echo     zip: %zip%
		echo.
		echo    test: %test%
		echo   test2: %test2%
	)
) else (
	echo Not successful.
)

This is the output from a brand new instance of cmd:

C:\Users\RandomClown\Desktop>test.bat
Version: 12345
   Type: 456

 Target: Client
    dir:
    zip:

   test: 42
  test2:

What you should notice is that the single line if statement correctly sets stuff. The multiline if will perform anything that is NOT a set. I dont think I missed anything. Also, the multiline if statement is correctly executing the right lines, as the else ( echo Not successful. ) lines did not execute.

Why did the lines not execute?

Windows Solutions


Solution 1 - Windows

You missed something ;-)

cmd expands variables when commands are parsed, not when they are run. It so happens that an if or for statement with a block ( ... ) (or actually any block) counts as a single command in that case. So when you set variables inside a block and try using them in the same block there are no variables anymore – they were replaced by the values the variables had before the block even executed.

Stick a

setlocal enabledelayedexpansion

at the start of your batch file and use !zip! instead of %zip%. See help set for a detailed discussion of the problem.

Solution 2 - Windows

Just a remind, the ms-dos "set" command takes every string after the equal sign. So if you write

if "x"=="x" set a=foo else set a=bar
echo %a%  // output : foo else set a=bar

The %a% is actually set to "foo else set a=bar", not foo. So I always use "()" for set command if there are multiple commands in one line.

if "%1"=="" (set a=20) else (set a=%1)    

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNyaariumView Question on Stackoverflow
Solution 1 - WindowsJoeyView Answer on Stackoverflow
Solution 2 - WindowsJack WuView Answer on Stackoverflow