Here is a working batch code:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem ...
if "%$ecbId%" == "" (
echo Enter '1' to blabla
echo Enter '2' to blabla
echo Enter anything else to abort.
echo/
set "UserChoice=abort"
set /P "UserChoice=Type input: "
if "!UserChoice!" == "1" (
echo toto1
rem save into property file
>>MDC.properties echo currentMaster=%ecb%
>>MDC.properties echo masterDcName=ECBDC
>>MDC.properties echo currentClone=%bdf%
>>MDC.properties echo cloneDcName=BDFDC
)
if "!UserChoice!" == "2" (
echo toto2
rem save into property file
>>MDC.properties echo currentMaster=%bdf%
>>MDC.properties echo masterDcName=BDFDC
>>MDC.properties echo currentClone=%ecb%
>>MDC.propertiesecho cloneDcName=ECBDC
)
if not "!UserChoice!" == "1" (
echo toto3
if not "!UserChoice!" == "2" (
echo toto4
echo Unknown input ... Aborting script
endlocal
exit /B 400
)
)
)
endlocal
Delayed expansion is enabled at top of the batch file with command setlocal EnableExtensions EnableDelayedExpansion
. The command SETLOCAL does not only enable delayed expansion, it saves entire command process environment on stack as explained in detail in my answer on change directory command cd ..not working in batch file after npm install. The command process environment is restored from stack on execution of command ENDLOCAL which would be also done by Windows command processor on exiting batch file processing when not explicitly executing endlocal
.
All environment variables set or modified in a command block starting with (
and ending with matching )
and also referenced within same command block must be referenced using delayed expansion.
When Windows command processor reaches the fourth line, the entire command block up to last but one line is parsed and preprocessed before the IF condition is evaluated at all. All environment variables referenced with percent signs are expanded on this preprocessing step in entire block from the line 4 to the line 36.
That means all occurrences of %ecb%
and %bdf%
are replaced by the current values of the environment variables ecb
and bdf
before the IF condition on line 4 is evaluated at all like %$ecbId%
in IF condition itself.
Just the environment variable UserChoice
is not expanded on parsing/preprocessing the entire block as this environment variable is referenced using delayed expansion.
Therefore it is possible to assign a default value like abort
to the environment variable UserChoice
kept in case of batch user hits just RETURN or ENTER without entering anything at all.
The string entered by the user is never expanded on a parsing/preprocessing stage because of using delayed expansion for environment variable UserChoice
. The current string value of UserChoice
is always interpreted on evaluating each IF condition.
This behavior of Windows command processor can be watched easily by
- removing
@echo off
from first line of batch file,
- opening a command prompt window,
- running in command prompt window the batch file by entering the name of the batch file with full path if current directory is not the directory of the batch file.
The Windows command processor outputs now always the line or command block after parsing before it is really executed. So it can be seen that on reaching first IF condition, the entire command block is already preprocessed with replacing all occurrences of %...%
with the appropriate strings from the environment variables respectively nothing if the reference environment variable is not defined yet. And it can be seen that the values of %ecb%
and %bdf%
are never modified again while next command lines within the entire command block are executed by Windows command interpreter.
More compact would be:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem ...
if "%$ecbId%" == "" (
echo Enter '1' to blabla
echo Enter '2' to blabla
echo Enter anything else to abort.
echo/
set "UserChoice=abort"
set /P "UserChoice=Type input: "
if "!UserChoice!" == "1" (
echo toto1
rem save into property file
>>MDC.properties echo currentMaster=%ecb%
>>MDC.properties echo masterDcName=ECBDC
>>MDC.properties echo currentClone=%bdf%
>>MDC.properties echo cloneDcName=BDFDC
) else if "!UserChoice!" == "2" (
echo toto2
rem save into property file
>>MDC.properties echo currentMaster=%bdf%
>>MDC.properties echo masterDcName=BDFDC
>>MDC.properties echo currentClone=%ecb%
>>MDC.properties echo cloneDcName=ECBDC
) else (
echo Unknown input ... Aborting script
endlocal
exit /B 400
)
)
endlocal
Another solution is using the command choice
which is available by default since Windows Vista. It has the advantage that the user just needs to press one of three keys. Delayed environment variable expansion is not needed in this case as choice
exits with a value depending on the pressed key which is assigned to the environment variable errorlevel
which can be evaluated without delayed expansion even within a command block.
@echo off
rem ...
if "%$ecbId%" == "" (
echo Enter '1' to blabla
echo Enter '2' to blabla
echo Enter 'A' to abort.
echo/
%SystemRoot%\System32\choice.exe /C 12A /N /M "Type input:"
if errorlevel 3 (
echo Aborting script
exit /B 400
) else if errorlevel 2 (
echo toto2
rem save into property file
>>MDC.properties echo currentMaster=%bdf%
>>MDC.properties echo masterDcName=BDFDC
>>MDC.properties echo currentClone=%ecb%
>>MDC.properties echo cloneDcName=ECBDC
) else (
echo toto1
rem save into property file
>>MDC.properties echo currentMaster=%ecb%
>>MDC.properties echo masterDcName=ECBDC
>>MDC.properties echo currentClone=%bdf%
>>MDC.properties echo cloneDcName=BDFDC
)
)
The user has to press 1 resulting in choice
exiting with value 1
because of character 1
is specified as first character after option /C
, or key 2 to let choice
exit with value 2
, or key A (case-insensitive) resulting in an exit of choice
with value 3
as character A
was specified as third character in next argument string after option /C
. There can be additionally pressed Ctrl+C to exit batch file processing after an additional confirmation. All other key presses are ignored by choice
and result in a bell noise output for notification of the user about having pressed wrong key.
It is best nowadays to use the command choice
for such user prompts with just file name or with full qualified file name for maximum execution safety.