3

A .bat should compare user input with a value. It doesn't go inside the IF "%choice%"=="1" when I test it with an input of 1 or 2.

Here is the batch file :

@echo off
rem ...
IF [%$ecbId%] == [] (
    echo Enter '1' to blabla
    echo Enter '2' to blabla
    echo Enter anything to abort
    set /p choice="Type input: "
    IF "%choice%"=="1" (
        echo toto1
        rem save into property file
        echo currentMaster=%ecb%>> MDC.properties
        echo masterDcName=ECBDC>> MDC.properties
        echo currentClone=%bdf%>> MDC.properties
        echo cloneDcName=BDFDC>> MDC.properties
    )
    IF "%choice%"=="2" (
        echo toto2
        rem save into property file
        echo currentMaster=%bdf%>> MDC.properties
        echo masterDcName=BDFDC>> MDC.properties
        echo currentClone=%ecb%>> MDC.properties
        echo cloneDcName=ECBDC>> MDC.properties
    )
    IF NOT "%choice%"=="1" (
        echo toto3
        IF NOT "%choice%"=="2" (
            echo toto4
            echo Unknown input ... Aborting script
            exit /b 400
        )
    )
)

The command output:

Enter '1' to blabla
Enter '2' to blabla
Enter anything to abort
Type input: 1
toto3
toto4
Unknown input ... Aborting script

Why is it not going inside the IF "%choice%"=="1" condition?

Mofi
  • 46,139
  • 17
  • 80
  • 143
Cedric
  • 977
  • 2
  • 11
  • 23

2 Answers2

10

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

  1. removing @echo off from first line of batch file,
  2. opening a command prompt window,
  3. 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.

Mofi
  • 46,139
  • 17
  • 80
  • 143
3

the following code might be able to help you

@echo off
echo Enter '1' to blabla
echo Enter '2' to blabla
echo Enter anything to abort
set /p choice="Type input: "

IF "%choice%"=="1" goto echoto1         

rem enter anything here you want it to do if variable is not met

:echoto1
rem start's here if the variable was met
echo toto1
@echo currentMaster=%ecb%>> MDC.properties
@echo masterDcName=ECBDC>> MDC.properties
@echo currentClone=%bdf%>> MDC.properties
@echo cloneDcName=BDFDC>> MDC.properties