3

I'm trying to adjust a Windows batch variable within a loop using the set /p command. After the keyboard input the variable still contains the old value. I have read that the variable set via set /p has only local scope. But I do not understand what "local" really means here.

@echo off
setlocal EnableDelayedExpansion

set a=4
echo Inital A: %a%

:LoopLabel
MODE | find %a% >nul 2>&1
IF %ERRORLEVEL% NEQ 0 (
    set /p "a=enter new a: "
    echo a=%a%
    goto LoopLabel
)

The output is:

Inital A: 4
enter new a: 5
a=4
enter new a: 6
a=5
enter new a: 7
a=6

Does anyone have an idea and can me explain why this is happening?

Many Thanks, Jonny

Jonny Schubert
  • 1,393
  • 2
  • 18
  • 39

1 Answers1

6

Executing code inside the IF is the problem. Check this out:

@echo off

set a=4
echo Inital A: %a%

:LoopLabel
MODE | find "%a%" >nul 2>&1
IF %ERRORLEVEL% EQU 0 goto stuff
    set /p "a=enter new a: "
    echo a=%a%
    goto LoopLabel
:stuff

The set /p is executed outside of the IF, so it works fine even without delayed expansion.

All of the commands inside the IF block get evaluated at the same time (in parallel), so when

echo a=%a%

runs, it is unaware of any new value assigned by

set /p "a=enter new a: "

To further clarify, your a does in fact contain the new value, but the echo a=%a% was executed using the old value.

One solution is to use IF and labels to get the expected program flow, while avoiding multi-step execution within an IF block.

Also you're going to get an error from find unless either your entered value is quoted or you add quotes around %a% when you feed it to find.

Alternatively you can use delayed expansion on your a value to get its value "after" set /p has changed it.

To do this, you would change

echo a=%a%

to

echo a=!a!

The only variable scope that I know of in batch is the %1...%9 and %* in called labels. Otherwise everything is global, including your a set by set /p.

LinuxDisciple
  • 2,289
  • 16
  • 19
  • Executing code inside an if shouldn't be a problem! Your solution is a workaround. I hope there are other solutions as well. – Jonny Schubert Sep 28 '16 at 16:12
  • Shouldn't be... Hmm. I think you're wishing you were using a better scripting language. – LinuxDisciple Sep 28 '16 at 16:12
  • 2
    Maybe you were hoping enabledDelayedExpansion would be more helpful. Try `echo a=!a!` – LinuxDisciple Sep 28 '16 at 16:16
  • Yeah I really wish to use a better language... But I have to :-( Using delayed expansion is working! Thank you for your help guys. – Jonny Schubert Sep 28 '16 at 16:25
  • @JonnySchubert, not sure why you accepted this as the answer. The code in its current form is not correct. – Squashman Sep 28 '16 at 16:44
  • 1
    There are two forms, one with delayed expansion and one without. They both work. The answer also addresses the other parts of his question. Care to explain what you mean by "not correct"? I'd be happy to fix any inaccuracies. – LinuxDisciple Sep 28 '16 at 17:57