Alphaceph
Alphaceph

Reputation: 115

CMD/Batch:userinput inside a for loop

I'm trying to take inputs inside a for loop. But inputs are not assigned to the input variable.

@echo off
echo Enter something for 3 times
for %%i in ( 1 2 3 ) do ( 
set /p usr=""
echo "You entered %usr%"
)

pause

The line

echo "You entered %usr%"

is just printing "You Entered ". So what am I doing wrong here?

Upvotes: 2

Views: 4868

Answers (1)

Andriy M
Andriy M

Reputation: 77677

They are assigned. It is the displaying that does not work as expected.

You've got a bracketed block of commands here, which is the loop body:

… ( 
set /p usr=""
echo "You entered %usr%"
)

Bracketed blocks are parsed entirely before the block starts executing. The %usr% expression, therefore, gets evaluated (substituted with its value at the moment) before the block executes. By the time of execution of the echo command there's no %usr% there anymore, but an empty string which was usr's value at the time of parsing.

So, what you need is delayed expansion. It is enabled by this command:

SETLOCAL EnableDelayedExpansion

and it stays in effect until either end of batch of or the ENDLOCAL command is reached.

Also, for delayed expansion you must use a different syntax: instead of %usr% use !usr!.

Here's your script modified so as to use delayed expansion:

@echo off
echo Enter something for 3 times
for %%i in ( 1 2 3 ) do ( 
set /p usr=""
setlocal EnableDelayedExpansion
echo "You entered !usr!"
endlocal
)

pause

One more thing to remember: because the mode is introduced with a variant of SETLOCAL command, that means all the changes to environment variables are local within the scope of the SETLOCAL command (i.e. until ENDLOCAL is executed or until the end of script). Alternatively you could simply enable the mode at the beginning of the script and never switch it off until the end, but in that case you would have to worry about any !s that might occur in user input.

Upvotes: 6

Related Questions