Batch: The goto statement isn't working properly - batch-file

I have three different labels, but it doesn't matter with one I choose: It will always got to the first label (= cmd is also opening if i am writing "google")! What's the error and why is it happening?
#echo off
:start
set /p input = What do you want to open?
if "%input%" == "cmd" goto cmd
if "%input%" == "notepad" goto notepad
if "%input%" == "google" goto google
:cmd
start
goto start
:notepad
start notepad
goto start
:google
start https://www.google.at/
goto start

Your first problem is in this line
set /p input = What do you want to open?
This line creates a variable called "input " with a space after it, and which is different than the "input" variable you're testing. Unlike every other programming language, you can't add spaces to beautify your code. Change the line to
set /p "input=What do you want to open? "
Your second problem is that after all three if statements fail (because of testing the wrong variable), CMD simply executes the next line it sees, which is the :cmd label. To avoid this, you need to add a default label after your three if statements, for when the variable doesn't match.
if "%input%" == "cmd" goto cmd
if "%input%" == "notepad" goto notepad
if "%input%" == "google" goto google
goto default
:cmd
start
goto start
If you just want the script to end there and don't want to create a :default block, you can change it to goto :eof, which is a special label for the end of the script. Or even better, use exit /B 1 which terminates the script immediately with an error code of 1 (which another script can check using %errorlevel%)

Your set /p isn't working as you think it should. input ends up empty and it falls through all of your if statements and right into the :cmd block.

Related

In Batch, Why is it that "not ", ignores the "if else" command and runs the next code anyway?

code:
echo To Start, type start
echo To view Options, type options
echo To Quit Game, type quit
set /p input= Command?
if %input% == start goto Start
if %input% == options goto Options
if %input% == quit goto Exit
else (
goto Menu
)
Basically what it should do is typing one of those choices will go to that part of the code, and typing something that isn't specified will run that script again. This works as intended, but my problem is when I type "not blah" (without quotes, where blah could be anything) it runs the script despite there not being specified action for blah in the code.
Why?
Besides the fact that you did not double quote your variables when comparing, you cannot use else like that. Else has to be on the same line as the closing parenthesis of the previous if statement and the opening parenthesis of the else code block. i.e: ) else (
Anyway to eliminate the need to accommodate for user errors in typing commands just use choice:
#echo off
:menu
choice /c SOQ /M "[S]tart, [O]ptions, [Q]uit"
goto opt%errorlevel%
:opt1
Echo this is the start section
goto :eof
:opt2
echo this is the Options section
goto :eof
:opt3
echo This is the Quit section
exit
:opt0
Goto menu

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?
1. Documentations for the Windows commands
I suggest bookmarking in your browser:
Microsoft's command-line reference
An A-Z Index of the Windows CMD command line (SS64)
There can be get help for each Windows command by running in a command prompt window the command with /? as parameter, for example if /?, set /?, ... The execution of help results in an output of an incomplete list of Windows commands with a brief description.
2. Usage of SET /P for user prompts
It is advisable not using set /p if the user should choose from one of several offered options. There are multiple facts which must be taken into account on prompting a user for entering a string and assigning it to an environment variable:
The environment variable MyVar is not modified on usage of set /P "MyVar=Your choice: " if the user presses intentionally or by mistake just RETURN or ENTER. This means if the environment variable MyVar is not defined already before the user prompt, it is still not defined after the user prompt finished with just hitting key RETURN. And if MyVar is defined already before the user prompt, it keeps its value unmodified in case of the user presses just RETURN or ENTER. The command SET exits with error value 1 on user did not enter a string at all as documented by What are the ERRORLEVEL values set by internal cmd.exe commands?
The user has the freedom to type any string on being prompted with set /P. The batch file author has no control on what the user really enters. So the batch file author 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.
exit /B
:Label2
#echo Option 2 was chosen, okay.
This batch file with echo on instead of echo off at 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 the batch file 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.exe encounters this syntax error and exits batch processing with an appropriate error message. The reason is the missing definition of environment variable menu which is not defined before user prompt and is still not defined after user prompt.
The string 2 is entered on second run of the batch file from within command prompt window 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 menu is 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.
exit /B
:Label2
#echo Option 2 was chosen, okay.
This is already better as now environment variable menu is always predefined with value 2. So if the user enters nothing, a jump to Label2 is done. Also the value of previous run of variable menu has no effect anymore on execution of the batch file.
Another solution would be making use of exit code 1 on user not entering a string at all and define only in this case the environment variable with a default value by using:
#set /P "menu=Your choice: " || set "menu=2"
Single line with multiple commands using Windows batch file describes the conditional execution operator || to run the second command set "menu=2" only if the first executed prompt command set /P "menu=Your choice: " exits with an exit code not equal 0 as done when the user does not enter anything at all.
Thanks aschipfl for this contribution.
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 " instead of 2 which 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 file 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?
A user prompt can be made fail safe and secure by using delayed variable expansion at least for the code evaluating the string input by the user.
#echo on
:MainMenu
#setlocal EnableDelayedExpansion
#set "Label=MainMenu"
#set /P "menu=Your choice: " || set "menu=2"
if "!menu!" == "1" set "Label=Label1"
if "!menu!" == "2" set "Label=Label2"
endlocal & goto %Label%
:Label1
#echo Option 1 was chosen, fine.
exit /B
:Label2
#echo Option 2 was chosen, okay.
Now the user input string does not modify anymore the command lines executed by Windows command processor. So an exit of batch file processing because of a syntax error caused by user input is not possible anymore (fail safe). Furthermore, the batch file never executes commands not written in batch file (secure).
3. Usage of CHOICE for a choice prompt
There is a better command than set /P for 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 exit /B
if errorlevel 2 goto Label2
if not errorlevel 1 goto MainMenu
#echo Option 1 was chosen, fine.
exit /B
:Label2
#echo Option 2 was chosen, okay.
The user has no freedom anymore to enter something not defined by batch file author. The batch file continues immediately after the user has pressed either 1, 2, E or Shift+E. Everything else is ignored by choice with exception of Ctrl+C.
The dynamic variable ERRORLEVEL has with three options nearly always a value in range 1 to 3 after choice terminated with returning 1 to 3 as exit code to calling cmd.exe. The exception is the rare use case that the user of a batch file pressed Ctrl+C on prompt and answers the next prompt Terminate batch job (Y/N)? of cmd.exe with N. In this case the dynamic variable ERRORLEVEL has the value 0 which is the reason for if not errorlevel 1 goto MainMenu to handle also this very special use case.
Note: if errorlevel X means IF GREATER OR EQUAL X. So it is always necessary to start with highest possible exit code of command choice.
As the exit code assigned to ERRORLEVEL is well known, it is possible on larger menus to optimize the code further by using appropriate labels:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ERRORLEVEL="
: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: "
goto Label%ERRORLEVEL%
:Label0
rem The user pressed Ctrl+C and on next prompt N and
rem so made no choice. Prompt the user once again.
goto MainMenu
:Label1
#echo Option 1 was chosen, fine.
exit /B
:Label2
#echo Option 2 was chosen, okay.
exit /B
:Label3
The usage of command CHOICE can make choice menus very simple to code.
The third command line makes sure that there is not defined by chance an environment variable with name ERRORLEVEL which would otherwise prevent accessing the current value of dynamic variable ERRORLEVEL using with the exit code of command CHOICE using the syntax %ERRORLEVEL%.
Note: The usage of goto Label%ERRORLEVEL% is only possible with the choice menu command lines not being inside a command block starting with ( and ending with a matching ).
See also: How can I make an "are you sure" prompt in a Windows batch file?
Hint 1: There is a beep sound output by CHOICE if the user presses a not acceptable key. It is not possible to suppress that beep as there is no option offered by CHOICE to avoid output of the beep sound.
Hint 2: See also my answer on Where does GOTO :EOF return to? explaining also exit /B.

My batch variable saver keeps crashing

This is what I have right now:
:saveDetector
if exist %USERPROFILE%/Desktop/savefile.txt
goto :saveDetectorName
else goto :name
:saveDetectorName
if exist %USERPROFILE%/Desktop/savename.txt
set /P c=Save detected. Would you like to load it?[Y/N]
if /I "%c%" EQU "Y" goto :saveloader
if /T "%c%" EQU "N" goto :choice
goto :saveDetectorName
:saveloader
set /p save=<savefile.txt
set /p name=<savename.txt
goto :%save%
I've attempted to go and fix it by doing things like fix the variables in the text files, use several branches, and stuff like that. However, it keeps crashing. Anyone know why? (And yes, the text files only contain 1 line)
if exist %USERPROFILE%/Desktop/savefile.txt
goto :saveDetectorName
else goto :name
The syntax of an if statement is specific.
the command to be executed must be on the same line as the if or at least start on the same line if that command is a code block (parenthesised sequence of lines)
If an else clause is used then the if-true command must be parenthesised and the closing parenthesis, the else keyword and the opening parenthesis of the if-false command must all be on the same line and separated by spaces.
if exist %USERPROFILE%/Desktop/savefile.txt (
goto saveDetectorName
) else (
goto name
)
The colons are not required in a goto.
If you run thecode directly from the prompt, you will get a syntax-error report shown on-screen.
/ is used to indicate a switch in windows. \ is used to separate directories. Sometimes, but not always / will be translated.

Call batch within batch?

How do I call multiple batch files within a single batch? When I try it always goes to the same one or none at all and closes window.
#echo off
:MENU
title MENU0
Echo 1 - Select Menu 1
Echo 2 - Select Menu 2
Echo 0 - Exit
Echo.
SET /P choice=Type the number or letter of task you want, then press ENTER:
IF %choice%==1 GOTO 1
IF %choice%==2 GOTO 2
IF %choice%==0 EXIT
:1
call %userprofile%\desktop\\Menu1.bat
:2
call %userprofile%\desktop\Menu2.bat
There are several issues with provided batch code in question.
The first one is that after processing of the batch file called with command CALL finished, the processing of current batch file continues with the next command respectively line, except the called batch file contains itself the command EXIT without parameter /B as in this case the command processor terminates itself independent on calling hierarchy.
For details about CALL behavior see answers on:
How to call a batch file in the parent folder of current batch file?
In a Windows batch file, can you chain-execute something that is not another batch file?
The second issue is that folder path assigned to environment variable USERPROFILE could contain 1 or more spaces (default on Windows 2000/XP, possible on later Windows versions depending on user name). Therefore always enclose a string referencing USERPROFILE or USERNAME in double quotes.
The third and most difficult to handle issue is that the user of a batch file on prompt with set /P has the freedom to enter anything and not just what the writer of the batch file suggests.
For example
SET /P choice=Type the number or letter of task you want, then press ENTER:
IF %choice%==1 GOTO 1
results in an exit of batch processing caused by a syntax error if the batch user hits just RETURN or ENTER without entering anything at all and the environment variable choice is not already defined with a useful string because in this case the next line to process by command processor is:
IF ==1 GOTO 1
It is good practice to define the environment variable with a default value before set /P as this value is kept when the batch user just hits RETURN or ENTER.
A batch user has also the freedom on using set /P to enter anything including syntax critical characters like " or < or | or > and others by mistake or intentionally (for breaking batch processing by a syntax error).
Therefore it is in general better for menus in batch files to use the command choice (Microsoft article) because then the batch user can enter only what the writer of the batch file offers. But CHOICE is available only by default for Windows Server 2003 and later Windows. And there are different versions of choice (SS64 article with additional information) with a different set of options. So it depends on which Windows version(s) the batch file is designed for if CHOICE can be used at all.
It is also not good to name an environment variable or a label like a command although possible. Therefore choice is not a good name for an environment variable.
Here is a commented batch file with a code which avoids all those issues.
#echo off
:MainMenu
setlocal EnableDelayedExpansion
title MENU0
cls
echo 1 - Select Menu 1
echo 2 - Select Menu 2
echo 0 - Exit
echo.
rem Define 0 as default value in case of user just hits RETURN or ENTER.
set "UsersChoice=0"
set /P "UsersChoice=Type the number or letter of task you want, then press ENTER: "
rem Has the user really entered just one of the offered characters?
rem There must be nothing to process if the user has entered just 0
rem or 1 or 2. Otherwise the user's choice was either by mistake or
rem intentionally entered wrong. The string entered by the user is
rem referenced with delayed expansion to avoid an exit of batch
rem processing in case of user entered a syntax critical character.
for /F "tokens=1 delims=012" %%I in ("!UsersChoice!") do (
endlocal
goto MainMenu
)
rem Now it is safe to reference the variable value without usage of delayed
rem expansion as a syntax error caused by user input can't occur anymore.
rem The entered string does not contain any not expected character. But
rem it is possible that for example 11 was entered by mistake instead
rem of just 1. The entered string should have a length of 1 character.
if not "%UsersChoice:~1,1%" == "" (
endlocal
goto MainMenu
)
rem Exit this batch processing on user entered 0. Previous environment is
rem automatically restored by command processor by an implicit endlocal.
if "%UsersChoice%" == "0" exit /B
rem Restore previous environment as the called batch files are most
rem likely written for using standard command environment with delayed
rem expansion not enabled (exclamation mark interpreted different).
rem The current value of local environment variable must be passed
rem to previous environment for usage on GOTO command.
endlocal & goto Menu%UsersChoice%
:Menu1
call "%USERPROFILE%\Desktop\Menu1.bat"
goto MainMenu
:Menu2
call "%USERPROFILE%\Desktop\Menu2.bat"
goto MainMenu
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
cls /?
echo /?
endlocal /?
exit /?
for /?
goto /?
rem /?
set /?
setlocal /?
title /?
For meaning of & in line endlocal & goto Menu%UsersChoice% see answer on Single line with multiple commands using Windows batch file.
I tried your code and what I found was that when the input was 1 both :1 and :2 are executed but when the input is 2 only :2 is executed. To fix this you need to specify the end of :1 using Exit or another goto.
You might see that none the batches are being executed IF you do not put a pause in the end of your script. They would be executed but the result might just flash out of the screen.
Also I do not understand why have you used \\Menu1.batand not \Menu1.bat in
:1
call %userprofile%\desktop\\Menu1.bat
The final working code for me-
#echo off
:MENU
title MENU0
Echo 1 - Select Menu 1
Echo 2 - Select Menu 2
Echo 0 - Exit
Echo.
SET /P choice=Type the number or letter of task you want, then press ENTER:
IF %choice%==1 GOTO 1
IF %choice%==2 GOTO 2
IF %choice%==0 EXIT
:1
call yourpathhere\Menu1.bat
pause
GOTO cont
:2
call whatsoever\Menu2.bat
pause
GOTO cont
:cont
exit
That should fix your problem.
Hope I helped.
I may not be a pro, but I could help you!
I always add extra code on my games in order to avoid bugs, like this:
set /p letter=
if %letter% == 1 goto nocheck1
if %letter% == 2 goto nocheck2
if %letter% == 3 exit
:nocheck1
if %letter% == 1 goto saves
:nocheck2
if %letter% == 2 goto howtoplay
Maybe it could work on your problem!
I might have the code to do it:
#echo off
cls
:menu
cls
echo 1. Open Batch 1
echo 2. Open Batch 2
set /p test=Enter number here ----->
if %test% == 1 goto check1
if %test% == 2 goto check2
Edit the "Batch file name" text with your location of your batch file.
:check1
if %test% == 1 start C:\Users\%username%\Desktop\(batch file name).bat
:check2
if %test% == 2 start C:\Users\%username%\Desktop\(batch file name).bat
If there's still any errors with my code, let me know.
Hope this helps your problem!
Use cd to go to the location of batch file. For example:
rem myscript
echo calling batch file
cd demo\desktop\script
execute.bat
echo done
After the execution of that batch, control will return to the next line of your script.
Use "Start" instead of "Call" like so,
#echo off
:MENU
title MENU0
Echo 1 - Select Menu 1
Echo 2 - Select Menu 2
Echo 0 - Exit
Echo.
SET /P choice=Type the number or letter of task you want, then press ENTER:
IF %choice%==1 GOTO 1
IF %choice%==2 GOTO 2
IF %choice%==0 EXIT
:1
start %userprofile%\desktop\\Menu1.bat
:2
start %userprofile%\desktop\Menu2.bat
Try This:
#echo off
:MENU
title MENU0
Echo 1 - Select Menu 1
Echo 2 - Select Menu 2
Echo 0 - Exit
Echo.
SET /P choice=Type the number or letter of task you want, then press
Enter:
IF %choice%==1 GOTO 1
IF %choice%==2 GOTO 2
IF %choice%==0 EXIT
:1
cd users
cd %userprofile%
cd desktop
:: call Menu1.bat or use: start Menu1.bat
:: exit
:2
cd users
cd %userprofile%
cd desktop
:: call Menu2.bat or use: start Menu2.bat
:: exit
start "" C:\location\of\file\file.bat
This opens a new window, and as long as you have more commands to follow, the previous file that is calling the new one will still run along with this one.

Goto not working correctly in batch?

I have a few things set up in a batch game. Instead of going where it is supposed to when the sure enters an option and hits "Enter" it goes to the next thing that starts with a : (I don't know what it is called).
Instead of it going to "Youtube" when the user types "Y".
:visitoption
echo Would you like to visit the RST Garry's mod gaming community website?
set /p option=Y or N:
if %option%==Y start chrome (Censored link)
if %option%==N cls goto :youtube
if %option%==y start chrome (Censored link)
if %option%==n cls goto :youtube
:version
cls
#echo off
echo.
echo[
#echo off
echo.
echo[
echo --Version--
echo Lightup Demo
#echo off
echo.
echo[
#echo off
echo.
echo[
#echo off
echo.
echo[
pause
goto :versionwhite
:youtube
echo Would you like to visit the Creator's Youtube channel?
echo Gameplay commentarys and such.
set /p option=Y or N:
if %option%==Y start chrome (Censored link)
if %option%==N goto :Beginning
if %option%==y start chrome (Censored link)
if %option%==n goto :Beginning
Essentially you were missing a command separator after the CLS but I've made some other changes such as /i case insensitive comparing and made the checking routines more robust to spaces or no input.
:visitoption
echo Would you like to visit the RST Garry's mod gaming community website?
set /p option=Y or N:
if /i "%option%"=="Y" start "" chrome "(Censored link)"
if /i "%option%"=="N" cls & goto :youtube
goto :visitoption
The "thing" is called a label
Since you have no control over what the user types, you should use
if "%option%"=="Y" start chrome (Censored link)
that is, quote both sides of the comparison (this is not bullet-proof, but serves adequately where the user is not deliberately trying to break your system.)
Adding the /i switch to the if will make the comparison case-insensitive.
if defined option set "option=%option:~0,1%"
will set option to just the first character.
Note that if the user replies simply Enter then the value of the variable remains unchanged. You can use this characteristic to your advantage
set "option=defaultvalue"
set /p option=Y or N:
will set option to defaultvalue if the user replies simply Enter.
start will start a process independently. The batch simply carries on to the next statement. You are probably beter off using start "window title for this instance" ... - it's a quirk of start that the first "quoted parameter" is used as the window title where you may be expecting it to be used as a parameter.
To concatenate a series of commands in a single line, you need to separate the individual commands with an ampersand &
Once you've turned echo off once, you don't need to do it again (unless you execute echo on, which you can do during debugging to show the program flow.) The leading # means don't echo this command - without it, the initial ECHO OFF would be reproduced.
You can use call :label to execute a subroutine that starts at :label in this batch file. If you use call label then the "subroutine" executed is the executable label. This is a very important distinction.
For this reason, I eschew the use of goto :label - although it works - because the colon is not necessary and for congruence between the goto and call commands.
The one exception to this omit-the-colons approach is where the colon actually does have an effect - goto :eof very specifically means 'goto the physical end of this batch file' - the label :eof is understood by cmd to have that meaning, and should not be defined in the batch.
You've set it so that it goes to youtube when the user presses n, not when the user enters y like you said your trying to in the question:
if %option%==N cls goto :youtube
Please try seeing what the cod eyour using is doing before you post a question on it.
And SO has one of the worlds easiest CodeSlabing systems. HOW BLOODY HARD IS IT TO PRESS SPACE 4 TIMES OR HIGHLIGHT AND PRESS THE "Code Sample" BUTTON?
Mona.

Resources