Environment variables should never begin with a digit and using a digits for loop variables should be also avoided. Run in a command prompt window call /?
and output is the help for this command explaining how batch file arguments can be referenced with %0
, %1
, %2
, ... which explains why environment variables with digit as first character and loop variables with a digit are not good in general even on being
a%num%
in set of FOR does not reference the value of environment variable a1
or a2
or a3
or a4
or a5
. It is just the name of the environment variable. The for
loop is not necessary at all.
@echo off
title var test
:question
set "a1=This"
set "a2=Is"
set "a3=a"
set "a4=Var"
set "a5=Test"
%SystemRoot%\System32\choice.exe /C 12345E /N /M "Press a number in range 1-5 or E for exit: "
if errorlevel 6 goto :EOF
set "num=%ERRORLEVEL%"
set /P "a%num%=Now change the answer: "
echo %a1% %a2% %a3% %a4% %a5%.
call echo You typed: %%a%num%%%
pause
goto question
The command line call echo You typed: %%a%num%%%
is parsed by Windows command processor before execution of the command line on number 3
entered to call echo You typed: %a3%
. This command line is parsed a second time because of command call
resulting in replacing %a3%
by the value of environment variable a3
and so echo
outputs the expected string.
It would be also possible to replace call echo You typed: %%a%num%%%
by
setlocal EnableDelayedExpansion
echo You typed: !a%num%!
endlocal
The usage of delayed environment variable expansion results also in double parsing the command line before execution of command echo
. For more details see How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Please read also this answer for details about the commands SETLOCAL and ENDLOCAL.
The two lines below in batch code above are also not really good taking into account that the user can really enter anything.
echo %a1% %a2% %a3% %a4% %a5%.
call echo You typed: %%a%num%%%
For example if the user enters number 1
and on next prompt enters:
Your user name is:& setlocal EnableDelayedExpansion & echo !UserName!& endlocal & rem
Then the batch file does something completely different than designed for and outputs the user's account name.
Secure would be the batch code:
@echo off
title var test
setlocal EnableExtensions DisableDelayedExpansion
:question
set "a1=This"
set "a2=Is"
set "a3=a"
set "a4=Var"
set "a5=Test"
%SystemRoot%\System32\choice.exe /C 12345E /N /M "Press a number in range 1-5 or E for exit: "
if errorlevel 6 goto :EOF
set "num=%ERRORLEVEL%"
set /P "a%num%=Now change the answer: "
setlocal EnableDelayedExpansion
echo !a1! !a2! !a3! !a4! !a5!.
echo You typed: !a%num%!
endlocal
pause
goto question
Now the user input string cannot modify anymore the command lines executed by Windows command processor.
A solution with the useless FOR loop would be:
setlocal EnableDelayedExpansion
for /F tokens^=1-6^ eol^= %%A in ("!a1! !a2! !a3! !a4! !a5! !a%num%!") do echo %%A %%B %%C %%D %%E.&echo You typed: %%F
endlocal
eol=
is necessary to output everything correct also if use enters number 1
and next a string starting with a semicolon. The FOR options string cannot be enclosed in double quotes in this case like "tokens=1-6 eol="
because of this would define "
as end of line character and nothing is output if user enters number 1
and enters next a string starting with "
. The equal sign and the space must be escaped with ^
to be interpreted as literal characters by cmd.exe
on double parsing the entire for
command line before execution of command for
.
Note: The FOR loop solution does not work correct on user enters for first variable value the special command line string as posted above. So it is also not really secure.