Batch Script SET /p without a value - variables

Creating a batch script in Windows XP. Here's a snippet of code I'm having problems with:
::==============================================================::
::How many scripts are included in this program?
SET NumOfScripts=4
::==============================================================::
:mainmenu
CLS
ECHO [MAIN MENU]
ECHO Please choose from the following options to run a particular script:
set /p choice="[1] SCRIPT1.bat | [2] SCRIPT2.bat | [3] SCRIPT3.bat | [4] SCRIPT4.bat : "
IF %choice% EQU 1 CALL :SCRIPT1
IF %choice% EQU 2 CALL :SCRIPT2
IF %choice% EQU 3 CALL :SCRIPT3
IF %choice% EQU 4 CALL :SCRIPT4
REM Wrong Choices
IF %choice% GTR %NumOfScripts% (
(ECHO You have entered an invalid option. Please press any key to be taken back to the main menu.) & PAUSE & GOTO:mainmenu
)
IF %choice% LEQ 0 (
(ECHO You have entered an invalid option. Please press any key to be taken back to the main menu.) & PAUSE & GOTO:mainmenu
)
ECHO You have entered an invalid option. Please press any key to be taken back to the main menu
PAUSE & GOTO:mainmenu
Looking under REM Wrong Choice, the first two arguments work as they should, however, if the user enters in no value (just presses the enter key) it automatically terminates the script. I've added IF NOT DEFINED choice and that doesn't work... I also tried IF [%choice%]==[] and IF [%choice%] EQU [] and those don't work either.
Here's the funny thing... you enter an invalid digit, say 5 or -1, it will give the echoes and go back to the main menu as it should... THEN if you just press enter without a value inserted, it will echo and go back to the main menu as it should.
My question is how do you get it to recognize that the user did not enter a value for set /p on the first go?

You can initialize choice to some invalid value before set /p, e.g.:
SET choice=none
To print the appropriate error message, you can do
IF %choice% EQU none (
(ECHO You did not select an option.) & PAUSE & GOTO:mainmenu
)

Set /p doesn't change the content of a variable, if the user doesn't enter text.
So you can simply set your variable to nothing to detect if the user enter anything.
Set "choice="
Or you can use the errorlevel, as it is set to 1 if the input is empty
But be careful, as it doesn't reset it to 0. So you have to force it yourself before.
cd.
Set /p choose=
If %errorlevel%==1 goto empty
And you should use the variables with delayed expansion, as it is always safe.
Else a user can break your script with input like "&exit"

Related

Calling variables do not work, what to do?

Hey StackOverflow Community,
I am currently programming my own life simulator called "XinsLife". Currently I want to call a variable that I set before. But it just doesn't work. I tried everything on YouTube and SS64 and could not find what the error was. So I thought I'd ask on StackOverflow. I know this problem is basic and probably everyone can do this, but I am very new to Batch.
Any help would be appreciated.
I am currently at country choosing, so when I choose a country it has to do a variable of what I chose, then goto :savesettings, and display the country that I chose. But it does not work.
C o d e :
:countrychoosing
cls
title New Life -- Country choosing
echo.
echo Choose your country:
call :echo-align center "United States"
call :echo-align center "United Kingdom"
call :echo-align center "China"
call :echo-align center "India"
call :echo-align center "More countries to come soon!"
set /p choosecountry=
if "%choosecountry%" equ 1 (
set chosecountry = United States
goto savesettings
)
if "%choosecountry%" equ 2 (
set chosecountry = United Kingdom
goto savesettings
)
if "%choosecountry%" equ 3 (
set chosecountry = China
goto savesettings
)
if "%choosecountry%" equ 4 (
set chosecountry = India
goto savesettings
)
:savesettings
call %chosecountry%
echo You chose the country "%chosecountry%". Do you want to create a save file?
choice /C:YN
if "%errorlevel%" equ 255 goto savesettings
if "%errorlevel%" equ N goto continuetest
if "%errorlevel%" equ Y goto createsavefiletest
if "%errorlevel%" equ 0 goto savesettings
Why you should use "choice", not "set /p" to accept user-input.
When you use set /p "var=Some user prompt" then var is set to the string entered from the keyboard.
But note that if the user's response is simply Enter then var will remain unchanged
All fine in theory, if you can be certain that your users will never enter an unexpected string.
Suppose the user enters 2 to your first prompt
The if statement would be interpreted as if "2" equ 2 (
Since "2" and 2 are different, the if statement will be evaluated as false. You need if "%choosecountry%" equ "2" (
So the code now becomes if "%choosecountry%" equ "2" (
Suppose the user enters United Kingdom to your first prompt, instead of the expected 2.
The if statement would be interpreted as if "United Kingdom" equ "2" ( - well, that could be fixed with some more code.
But suppose the user enters UK -yes. More code...
Suppose the entry was x"y. This would lead to a syntax error - and there are oodles of other examples like %hello which the user could enter but batch would object to.
Well - most, but probably not all of these unexpected input strings could probably be massaged to allow the cmd processor to handle them smoothly, but that's a lot of unnecessary work and code.
The better solution is to use choice which you use (but incorrectly, sorry) later in your code.
If you enter choice /? from the prompt, you get a full description of choice. In summary, you can use the command choice /C:YN where YN can be any string of unique alphamerics - a to z or a digit.
choice waits for a single character and will beep if one of the choices set by the /c: is not used.
If one of the allowed options is used, then it sets the magic variable errorlevel to a value that depends on the position of the character within the allowed string, so pressing N in response to choice /C:YN would set errorlevel to 2; for choice /C:NY to 1; for choice /C:ORANGES to 4.
magic variables are those that are set automatically like DATE, TIME, RANDOM and others. These variables should not be set as part of a program as the value set into the variable then overrides the value that the system sets.
magic variables otherwise work identically to normal user-variables, and ALL VARIABLES are strings. If the string is purely numeric then the set /a command can be used to perform some mathematical operations. (there are some esoteric exceptions to the pure-numeric string requirement - see set /? from the prompt for details)
So, to structure a choice for use from a menu, you might have
choice /C:YN
if "%errorlevel%" equ "255" goto savesettings
if "%errorlevel%" equ "2" goto continuetest
if "%errorlevel%" equ "1" goto createsavefiletest
Note that each side of the if operator ("equ") must be quoted.
OR - you may have
choice /C:YN
if errorlevel 255 goto savesettings
if errorlevel 2 goto continuetest
if errorlevel 1 goto createsavefiletest
Note that these tests must be performed in reverse-numerical order as the meaning of if errorlevel n is "if errorlevel is n or greater than n"
You could even use
choice /C:YN
goto point%errorlevel%
where :point1 is located at :createsavefiletest, :point2 at :continuetest and :point255 at :savesettings.
Note that a label is simply a location in a file, so
some code...
:xyz
:abc
:hyg
some more code...
would mean that goto xyz,goto abc andgoto hyg all do exectly the same thing.
This should enable you to solve your problem.
Batch is sensitive to spaces in an ordinary string SET statement. SET FLAG = N sets a variable named "FLAGSpace" to a value of "SpaceN". Remove Space from both sides of the =.
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign " or a terminal backslash or Space. Build pathnames from the elements - counterintuitively, it is likely to make the process easier. If the syntax set var="value" is used, then the quotes become part of the value assigned.

How can I set the line a string is found on as a variable, and then find the contents of that line number in another file?

Okay, this is kind of complicated so ill try to explain it as best as is can.
I am currently writing a simple program for my own use using notepad.
I am using the language batch and running the program through Command Prompt.
Part of the Program lets you access an account you created with username and password:
set /p USERNAME1= Username?
findstr /n "%USERNAME1%" Usernames.txt
In Usernames.txt are the usernames of each account that has been created, one per line.
If your username is found, it is displayed along with the line number before it in the program.
It then asks for your password:
set /p PASSWORD1= Password?
This is where the problem starts. When the accounts are created, the usernames are stored, one per line, in Usernames.txt , and so are the passwords but in Passwords.txt
I need the program to check if the password you typed is the same as the password on the same line number the username is on, in Passwords.txt
I know this is complicated but if anyone can help it would be greatly appreciated!
Thanks
You're using findstr /N to get the line number of usernames.txt, which is a good start. You're getting the entire line, prefixed with the line number and a colon :.
So for /F can be used to extract the number only. The option string "tokens=1 delims=:" defines to divide the found line at the (first) :, so the line number is separated from the user name.
Finally, another for /F can be used to get the line of the passwords.txt files.
Putting all those things together, the following code snippet emerges:
set /P USERNAME1=Username?
set /P PASSWORD1=Password?
set /A LINENUMBER=0
for /F "tokens=1 delims=:" %%I in (
'findstr /N /I /X /C:"%USERNAME1%" "\path\to\usernames.txt"'
) do (
set LINENUMBER=%%I
goto :CONTINUE1
)
:CONTINUE1
set /A LINENUMBER-=1
if %LINENUMBER% lss 0 (
exit /B
) else if %LINENUMBER% equ 0 (
set SKIPPING=
) else (
set SKIPPING=skip=%LINENUMBER%
)
for /F "usebackq %SKIPPING% delims=" %%I in (
"\path\to\passwords.txt"
) do (
if "%%I" equ "%PASSWORD1%" (
goto :CONTINUE2
)
exit /B
)
:CONTINUE2
rem do something...
So the variable USERNAME1 holds the entered user name to search and PASSWORD1 the entered password.
If the user name cannot be found in usernames.txt, or the entered password does not match the found one, the script is terminated using exit /B.
Note that user names are compared in a case-insensitive manner (/I switch), but the password are compared case-sensitively.

Set variable equal to a number in a text file Batch

I have a batch file (tickets.bat) and each time you create a different ticket, by setting multiple variables and echoing the variables to a text file, I want the ticket number to go up by 1. I tried to do this by creating a number.txt file and each time you go through the loop and create a new ticket, it sets %pnumber% to the text file, and then sets %number% to %pnumber% plus 1. But %pnumber% keeps setting to 0, even when the number.txt file contains the number 1 and doesn't change. This is what I have:
:start
cls
echo Enter Ticket Info Here:
set /p name="Name:"
echo Press Enter to Show Ticket Preview
set /a pnumber=C:\Batch\ticket\number.txt
set /a number=%pnumber%+1
echo %number% > "C:\Batch\ticket\number.txt"
echo %name% Ticket Number %number%
pause
goto start
It looks like my problem is that %pnumber% always sets to 0. Unless I'm missing something else. Basically, I need it to always increase %number% by 1, even if you close the Batch job and open it up again, so that's why I went to using a .txt file. Is it not seeing the number in the text file or something? It's one number on one line. Thank you.
Try Like this :
#echo Off
:start
cls
echo Enter Ticket Info Here:
set /p name="Name:"
echo Press Enter to Show Ticket Preview
set /p pnumber=<C:\Batch\ticket\number.txt
set /a number=%pnumber%+1
echo %number% >C:\Batch\ticket\number.txt
echo %name% Ticket Number %number%
pause
goto start

Batch file waits until I press enter when set b=

I've encountered a bit of an issue in a Batch script I am making.
In this script, I want to it react to my pressing a button the moment I press it, and 'set'ting a new variable without having to press Enter.
Currently, it's like this;
set b=
set /p b=
ig %b%==a (
goto Success
)
It allows me to press the button I want, however I don't want it to wait until I press Enter afterwards.
For VISTA and later
If you know your script will run on Vista or later (not XP), then you can use the choice command. You must specify which characters to accept. By default, CHOICE is case insensitive. The returned ERRORLEVEL corresponds to the position of the selected letter within the choice list.
For example, to wait for the user to press A, B, or C (case sensitive) and store the key value in a variable:
setlocal enableDelayedExpansion
set "list=ABC"
choice /cs /c "%list%"
set "list=.%list%"
set "key=!list:~%errorlevel%,1!"
echo %key%
Full documentation is available from the command line by typing HELP CHOICE or CHOICE /?
For all modern Windows, including XP
I was introduced to a very clever solution that works on XP and beyond when I was developing my batch implementation of the SNAKE game. This solution allows you to capture nearly any key press.
set "key="
for /F "usebackq delims=" %%A in (`xcopy /w "%~f0" "%~f0" 2^>NUL`) do (
if not defined key set "key=%%A"
)
set "key=%key:~-1%"
set key
use choice in batch
choice /c YN /m "Is Yes"
if ( %ERRORLEVEL% == 1 ) (
ECHO "SUCCESS"
)

table==1 was unexpected at this time batch file

I am trying to apply multiple SQL scripts to an Ingres database (using a vnode setup). The testing phase will require it done to four databases. Trying to nip this annoyance in the bud I've started a batch file but receive the error above.
Many of the solutions found suggest that the batch file will evaluate everything within a block when it starts but I cannot see the forest for the trees. I have a suspicion that the parts in :1ST and :2ND are causing the problems but they need to be done.
SQL, Batch and command window output are below
UPDATE core SET sysflag='O'
#ECHO off
SET VN1=dave
SET DB1=dbtest1
SET DB2=dbtest2
SET SQL1=open.sql
SET SQL2=open.sql
:MENU
CLS
ECHO 1 - Leave
ECHO 2 - Database1
ECHO 3 - Database2
SET /P M=Choose then press ENTER:
IF "%M%"=="1" GOTO EOF
IF "%M%"=="2" GOTO 1ST
IF "%M%"=="3" GOTO 2ND
GOTO MENU
:1ST
SET DATABASE=%VN1%::%DB1%
GOTO RUNSQL
:2ND
SET DATABASE=%VN1%::%DB2%
GOTO RUNSQL
:RUNSQL
ECHO Applying SQLs to %DATABASE%
SQL %DATABASE% < %SQL1% > log_%SQL1%.txt
PAUSE
SQL %DATABASE% < %SQL2% > log_%SQL2%.txt
PAUSE
GOTO MENU
:EOF
C:\Users\me\BUILD>IF UPDATE core SET sysflag='O'==1 GOTO EOF
You are expecting the value of %M% to have 1, 2, or 3. But somehow the value is UPDATE core. The IF statement fails because there is a space in the middle of the left value. Token delimiters like space must be escaped, or the entire string on each side should be quoted. You could change your statement to IF "%M%"=="1" GOTO EOF to eliminate the error, but it still will not give the results you want.
The SET /P statement reads the value from stdin. I assume you have not typed the value UPDATE core, but instead your input was either redirected or piped. You are feeding your script the wrong value.
You should add error handling so that the code does not fall through to :1ST if the input is not 1, 2, or 3.
You can explicitly redirect input to the console for your SET /P statement. That way it will ignore the redirected input or piped input that was provided for the batch script.
<con: SET /P "M=Choose then press ENTER: "
But something seems wrong with your whole design. If you are piping or redirecting input for the script, then it doesn't make sense to present an interactive menu of choices in a loop. What happens if the user never presses 1 to quit? Eventually the piped or redirected input will be exhausted, and then you have problems.