How to stop Windows command interpreter from quitting batch file execution on an incorrect user input?
If I have the following example code:
@echo off :menu cls echo 1. win echo 2. lose set /p menu= goto %menu% pause>nul :win cls echo yay lolz pause>nul :lose cls echo really? pause>nul
How do I stop the batch from quitting if I type "test" instead of a valid response?
First, I suggest to bookmark in your browser:
You can get help for every Windows command by running in a command prompt window the command with
/?as parameter, for example
set /?, ...
Second, don't use
set /pif the user should choose one of several options. There are multiple facts which must be taken into account on prompting user for entering a string and assigning it to an environment variable:
On usage of
set /P "MyVar=Your choice: "the environment variable
MyVaris not modified if the user presses intentionally or by mistake just RETURN or ENTER. This means if the environment variable
MyVaris not defined already before the user prompt, it is still not defined after user prompt finished with just hitting key RETURN. And if
MyVaris defined already before user prompt, it keeps its value unmodified in case of user presses just RETURN or ENTER.
The user has the freedom to type any string on being prompted with
set /P. The batch file writer has no control on what the user really enters. So the batch file writer must take into account that the user enters by mistake or intentionally a string which could result in an exit of batch file execution because of a syntax error or it does something completely different as it is defined for.
A simple example:
@echo on :MainMenu @set /P "menu=Your choice: " if %menu% == 1 goto Label1 if %menu% == 2 goto Label2 goto MainMenu :Label1 @echo Option 1 was chosen, fine. goto :EOF :Label2 @echo Option 2 was chosen, okay.
This batch file with
echo oninstead of
echo offat top is started from within a command prompt window for debugging purposes.
Just RETURN is pressed on user prompt on first run. Windows command interpreter exits batch processing because first IF condition is preprocessed before execution of IF command to:
if == 1 goto Label1
There is obviously missing the first argument.
cmd.exeencounters this syntax error and exits batch processing with an appropriate error message. The reason is environment variable
menuis not defined before user prompt and is still not defined after user prompt.
On second run of the batch file from within command prompt window
2is entered and the batch file works as expected.
On third run of the batch file from within same command prompt window again just RETURN is pressed on user prompt. The batch file outputs again the second message. Why? The environment variable
menuis still defined from second batch file execution with that string and the variable was not modified on pressing RETURN.
Okay, let us modify the example batch file to:
@echo on :MainMenu @set "menu=2" @set /P "menu=Your choice: " if "%menu%" == "1" goto Label1 if "%menu%" == "2" goto Label2 goto MainMenu :Label1 @echo Option 1 was chosen, fine. goto :EOF :Label2 @echo Option 2 was chosen, okay.
This is already better as now environment variable
menuis always predefined with value
2. So if the user enters nothing, a jump to
Label2is done. Also the value of previous run of variable
menuhas no effect anymore on execution of batch file.
But is that really secure and fail safe now?
No, it isn't. The user still can enter by mistake a wrong string.
For example the user enters by mistake
2which is easy on German keyboards as CapsLock+2 or Shift+2 results in entering
". The first IF command line after preprocessing is now:
if """ == "1" goto Label1
And this is again an invalid command line resulting in an exit of batch file processing because of a syntax error.
Let us assume a user enters on prompt the string:
" == "" call dir "%USERPROFILE%\Desktop" & rem
Note: There is a space at end.
The first IF condition is preprocessed by Windows command interpreter to:
if "" == "" call dir "%USERPROFILE%\Desktop" & rem " == "1" goto Label1
It can be seen that the batch files executes now a command not written in the batch file at all on both IF conditions.
How to get a user prompt fail safe and secure?
By using delayed environment variable expansion at least around code evaluating the user input string.
@echo on :MainMenu @setlocal EnableDelayedExpansion @set "menu=2" @set "Label=MainMenu" @set /P "menu=Your choice: " if "!menu!" == "1" set "Label=Label1" if "!menu!" == "2" set "Label=Label2" endlocal & goto %Label% :Label1 @echo Option 1 was chosen, fine. goto :EOF :Label2 @echo Option 2 was chosen, okay.
Now the user input string does not modify anymore the command lines executed by Windows command interpreter. So an exit of batch file processing because of a syntax error caused by user input is not possible anymore. And the batch file never executes commands not written in batch file.
But there is a better command than
set /Pfor a simple choice menu – choice.
@echo off :MainMenu cls echo/ echo 1 ... Option 1 echo 2 ... Option 2 echo E ... Exit echo/ %SystemRoot%\System32\choice.exe /C 12E /N /M "Your choice: " if errorlevel 3 goto :EOF if errorlevel 2 goto Label2 @echo Option 1 was chosen, fine. goto :EOF :Label2 @echo Option 2 was chosen, okay.
The user has no freedom anymore to enter something not defined by batch file writer. The batch file continues immediately after the user has pressed either 1, 2, e or Shift+E. Everything else is ignored by
choicewith exception of Ctrl+C.
The environment variable
ERRORLEVELhas with three options always a value in range 1 to 3 after
choiceterminated with returning 1 to 3 as exit code to calling
if errorlevel Xmeans IF GREATER OR EQUAL X. So it is always necessary to start with highest possible exit code of command
As the exit code assigned to
ERRORLEVELis well known, it is possible on larger menus to optimize the code further by using appropriate labels:
@echo off :MainMenu cls echo/ echo 1 ... Option 1 echo 2 ... Option 2 echo E ... Exit echo/ choice.exe /C 12E /N /M "Your choice: " goto Label%ERRORLEVEL% :Label1 @echo Option 1 was chosen, fine. goto :EOF :Label2 @echo Option 2 was chosen, okay. goto :EOF :Label3
The usage of command CHOICE can make choice menus very simple to code.
Third, see also answer on Where does GOTO :EOF return to?