batch file display prompt not correct - batch-file

There are two issues with the batch below. The first is, when batch file when opened prompts the user with a "y/n" question:
Question 1
Has the check been done
If the answer to this is "y" then another "y/n" question is displayed
Question 2
Do you want to send the DOSE report
If the answer to question 1 is "n" the check function is called and another question is displayed. However, currently the line in bold is being displayed then it is going to the second part (the goodbye function). What am I doing wrong? Thank you :).
Current batch
#ECHO OFF
:: ask user
:choice
set /P c=Has the check been done [y/n]
if /i %c%==y (
set /P c=Do you want to send the DOSE report[y/n]?
) else (
if /i %c%==n goto check
)
if /i %c%==y (
"L:\NGS\HLA LAB\total quality management\QC & QA\DOSE reports\DOSE reporting form.xlsm"
) else (
if /i %c%==n goto goodbye
)
:check
set /P c=Do you want to perform the check [y/n]
if /i %c%==y (
echo "perform check and hit enter when complete"
pause goto choice
) else (
if /i %c%==n goto goodbye
:: count loop
set var1=0
:loop
set /a var1=%var1%+1
echo %var1%
if %var1% EQU 1 (
goto end
) else (
goto loop
)
:end
echo "the DOSE report has already been sent by %USERNAME% on %DATE% at %TIME%"
:goodbye
echo "goodbye"
TIMEOUT 2 /nobreak
exit

First off, the if-else statement in :choice is missing its closing )
Heres an important note on user input, never trust it. Try putting something other than y/n in the first
:choice
set /p c=Has the check been done [y/n]
if /i %c%==y (
set /p c=Do you want to send the DOSE report[y/n]?
) else (
if /i %c%==n goto check
)
If you input something invalid into the first if-else , say somebody tries typing no instead of n, it will fail to return them to :choice as it only checks for n or y
And end up running through script. In your case it fails the if statements before :check and starts :check's proccess, but in check the same issue arises, and it will run through to ::count loop and the following commands where it can mess up your data.
After each if-else statement, its VERY safe practice to add a default action, such as;
:choice
set /p c=Has the check been done [y/n]
if /i %c%==y (
set /p c=Do you want to send the DOSE report[y/n]?
) else (
if /i %c%==n goto check
)
:[ If both if statements are false, it will reach this line: ]
cls
echo Error: "%c%" is not y/n.
pause
goto :choice
Another thing to note, if nothing is input, errors will occur. You can fix this by checking if the variable is defined right after set /p c=Has the check been done [y/n] using:
if not defined c (
cls
echo Error: Input cannot be empty!
pause
goto :choice
)
So a proper way to do the first check would be:
:choice
set /p c=Has the check been done [y/n]
:[Empty check ]
if not defined c cls & echo Error: Input cannot be empty! & pause & goto :choice
if /i "%c%==y" (
set /p c=Do you want to send the DOSE report[y/n]?
) else (
if /i "%c%==n" goto check
)
:[ Invalid input ]
cls & echo Error: "%c%" is not y/n. & pause & goto :choice

To answer your question directly... well, I'm not sure what you're asking to be honest. I'm having trouble deciphering "I am trying to have the below batch file increment the counter %var1 only if the "y" and not able to get the syntax correct."
I don't see any outright syntax errors, but you do have quite a few logic issues with your script. Indeed, the value of %var1% is being incremented. Put an echo Var1 incremented: %var1% after the set /a var1+=1 and see for yourself. To fix your script, you need to address what statements get executed under what conditions.
Use setlocal. It's just good practice. Using setlocal helps you avoid contaminating the outer console thread with variables that are only relevant to the runtime of this script.
Don't trust that the user will always answer "y" or "n". What happens if they answer "w"? As your script is written, it will proceed to sections you probably didn't intend. I have two suggestions for this.
a. Don't explicitly check for an answer of "n". If it's not "y", assume it's "n". If that is not appropriate, then have a final else goto label for whatever label immediately precedes the conditional.
b. Alternatively, instead of set /P, consider using choice. Example:
choice /c YN /m "Do you want to perform the check? "
if errorlevel 2 (
rem // user chose "N"
) else (
rem // user chose "Y"
)
In your :choice section of code, what is the difference between an answer of Y then N, versus an answer of N? As written, there's no difference. Either way, the script proceeds to :check. Examine your logic here.
Instead of exit, consider using either exit /b or goto :EOF. When running your script from a cmd prompt (as opposed to double-clicking it), you should avoid exiting the parent thread.
For goodness sake, indent your code and add some line breaks! That big blob of left-justified commands has no flow, no rhythm. It's tedious to read and troubleshoot.
Before:
#ECHO OFF
:: ask user
:choice
set /P c=Has the check been done [y/n]
if /i %c%==y (
set /P c=Do you want to send the DOSE report[y/n]?
) else (
if /i %c%==n goto check
)
:check
set /P c=Do you want to perform the check [y/n]
if /i %c%==y (
set /P c=please complete the check and click enter
goto file
) else (
if /i %c%==n goto goodbye
)
It's like a slab, difficult to see at a glance which statements are ancestors and which are descendents or where the section breaks occur.
After:
#ECHO OFF
setlocal
:choice // ask user
choice /c YN /m "Has the check been done? "
if not errorlevel 2 (
choice /c YN /m "Do you want to send the DOSE report? "
if errorlevel 2 (
goto goodbye
)
)
:check
choice /c YN /m "Do you want to perform the check? "
if errorlevel 2 goto goodbye
set /P "c=Please complete the check and click enter: "
See? It's much more pleasant to read that way. By the way, you might've noticed that I combined the "ask user" comment with the :choice label. That's often done when defining functions to explain expected parameters, or just explain what's going on. You don't really need the double slashes. It just makes Stack Overflow's Ted Turner Technicolor parser demonstrate that that's a comment.

Related

Batch crashes with spaces even with var set and delayed expansion

I just started coding two days ago. (It's oddly addictive). And I started so that I could make a simulated "computer hacking" experience as a portion of an escape room that I am designing. Mainly, I have just been looking around and finding different ideas and putting them together in an aesthetically pleasing way. However, I want to make it crash resistant. So that when people are using it they don't get booted for just button mashing and pressing enter.
I got this to work in the :menu but not on the faux log in page.
Below is the code that I wrote that I want to be able to work on other pages:
:menu
cls
set "answer=Nothing^!"
set var=%var: =%
echo.
echo Menu
echo.
echo 1. Login
echo 2. Instructions
echo 3. Exit
echo.
set /p answer=Type the number of your option and press enter:
echo.
echo.
if /I "!answer!" == "exit" goto exit
echo You answered: %answer%
echo Which is not a valid entry.
echo Try again.
if /I %answer% == 1 goto :Login1
if /I %answer% == 2 goto :Instructions
if /I %answer% == 3 goto :Exit
if /I %answer% == 43153 goto :done
pause
goto :menu
Here is the code I cannot get to work.
:Login2
cls
set "un=Nothing^!"
set "pw=Nothing^!"
set var=%var: =%
echo.
echo Log On
echo.
if %counter% lss 5 echo Password incorrect, %counter% attempts left
echo.
echo.
set /p un=Enter your UserID:
set /p pw=Enter your Password:
if /I %un% == ID (
if /I %pw% == PASSWORD goto :loading1
)
if /I !un! == "exit" (
if !pw! == "exit" goto loading2
goto :loading2
If I type something random to input such as: asdf asdf
The menu doesn't crash. But the login2 page does. It crashes if it is username and password OR just username OR just password that have spaces. And if I just "enter" through the screen it does not auto-populate " Nothing^! " like the menu does.
I would paste the entirety of the file below, but because with the decorative liberties I took it won't fit well on this page. And I can't find a place to upload it. But any comments or suggestions would be greatly appreciated.
Again, thank you for any help!
if /I "!answer!" == "exit" goto exit
is correct
if /I %un% == ID (
is syntactically correct, provided un contains a simple string not containing spaces.
if un contains some spaces then the command is interpreted as
if /I some spaces == ID (
and the required syntax is
if [/i] string1 operator string2 dothis
An operator like == is also a string, so cmd sees spaces where it's expecting an operator, so it protests.
To allow spaces (and other separators) in a string, "quote the string" as you did with the first if above.
Oh - and it's particular about the quotes - they must exactly match - you can't quote one side and not the other.
This applies to string arguments only - where the arguments are numerics or resolve to a numeric, the quotes are not used. If they are used with numeric arguments, the arguments will be compared alphabetically so 98 is greater than 123 because 9 is greater than 1.
Always enquote variables in your IF expressions.
IF /i "%un%" == "ID" ...
IF /i "%pw%" == "PASSWORD" ...
or even better use delayed expansion here
IF /i "!un!" == "ID" ...
IF /i "!pw!" == "PASSWORD" ...

windows 7 bat file closes after user types response

I am trying to write a bat file that upon startup will prompt a user. I can get the user prompt but get an error and the bat file closes. Basically, if the answer is y then a vb at the path is called and if the answer is n then the bat exits. Is the syntax below close? Thank you :).
#ECHO OFF
:choice
set /P c=Do you want to send the DOSE report[y/n]?
if /I "%c%" EQU "Y" goto :L:\NGS\test_email_DOSE.xlsx
if /I "%c%" EQU "N" goto :exit
goto :choice
pause
exit
Try this:
#ECHO OFF
:choice
set /P c=Do you want to send the DOSE report[y/n]?
if /i %c%==y (
L:\NGS\test_email_DOSE.xlsx
) else if /i not %c%==n goto choice
pause
In this script the second if is only reached when the answer was not 'y'. Also, the goto you used always requires a label to jump to. A path is not a label.
I assume of course that L:\NGS\test_email_DOSE.xlsx is a valid path.
When I run it on my pc it produces the following (I saved the file as decide.cmd):
D:\tmp>decide
Do you want to send the DOSE report[y/n]?d
Do you want to send the DOSE report[y/n]?f
Do you want to send the DOSE report[y/n]?y // (the Excel file is opened)
Press any key to continue . . .
D:\tmp>
I'd probably go this way. The previous answer would do fine. But this approach looks cleaner in my opinion.
#ECHO OFF
:choice
SET /P c=Do you want to send the DOSE report [Y/N]?
IF /I %c%==Y (START "" "L:\NGS\test_email_DOSE.xlsx")
IF /I %c%==N GOTO :EOF
GOTO :choice

BATCH program crashes after goto command

This code is part of a chat program that I am currently working on. The 'else' part of my program is the one that doesn't work. The program quits instead of going to :home
:join
cls
if not exist "C:/Users/Public/room.cmd" (
echo No room has been found.
echo.
set /p choiceretry=Do you want to retry? y/n
if "%choiceretry%"=="y" goto join
if "%choiceretry%"=="n" goto home
) else (
cls
"C:/Users/Public/room.cmd"
echo A room has been found.
pause >nul
echo Joining
set roomjoined=1
echo %roomjoined%
goto home
)
:home
echo this finally works
pause
I have tried changing the code several times starting from 'echo Joining'
Anyone know why cmd quits?...
:) :) :)
Thanks in advance
The problem is the way you run room.cmd; you must use call to return from it:
call "C:/Users/Public/room.cmd"
Otherwise, execution will not return from room.cmd to the original batch file that ran it.
Hint: Consider to use choice instead of set /P for Y/N decisions.
Firstly, please don't left justify your code blocks. It's much easier to read code that's properly indented.
Secondly, when retrieving values within a code block, you need delayed expansion. See setlocal /? in a cmd prompt for more information. This is the reason for the unexpected behavior. Your variables retrieved within the same parenthetical code block in which they were set won't contain the values you expect unless you retrieve them with delayed expansion syntax. As an alternative, you could use the choice command and if errorlevel, which would result in a bit nicer user experience I think.
Thirdly, when testing user input, you should use the /i switch in your if statements for case-insensitivity. This isn't relevant if using choice / if errorlevel though.
Fourthly, Windows paths use backslashes, not forward slashes.
I'd fix it this way:
#echo off
setlocal
:join
cls
if errorlevel 1 set /P "=Retrying... "<NUL
if not exist "C:\Users\Public\room.cmd" (
echo No room has been found.
echo.
choice /c yn /n /m "Do you want to retry? [y/n] "
if errorlevel 2 goto home
goto join
) else (
"C:\Users\Public\room.cmd"
echo A room has been found.
pause >nul
echo Joining
set roomjoined=1
)
:home
echo this finally works
pause

How to find keywords of the users input in the command line?

What I'm looking for is a batch file line of code that will scan what the user inputs to find key words and direct them in the right place. That way when a trainee has a question he/she could just ask the batch file and it will direct them to the proper menu. Is this possible? if so, How would one go about doing this?
:menu
set /p c=Please type you question:
findstr /m "How to ringout a product on our system?" "%c%"
if %c%=="ringout" (
goto :Ringingout
) Else (
goto :Sorry
)
:Ringingout
cls
echo In order to right something out maksure you do the following:
echo - Log in
echo - click on scan in the bottom left had corner on the tender page
echo - scan items
echo - click continue
Pause
goto :Menu
:Sorry
cls
echo Sorry I don't recognize your question, please re-word it.
pause
goto :Menu
#ECHO OFF
SETLOCAL
SET "keywords=word anotherword someword"
FOR %%k IN (%keywords%) DO set "#%%k="
SET /p query="Please enter your query ? "
FOR %%k IN (%keywords%) DO CALL :analyse %%k
SET #
GOTO :EOF
:analyse
CALL SET "found=%%query:%1=%%"
IF "%found%"=="%query%" GOTO :EOF
SET #%1=FOUND!
GOTO :eof
Here's a general way to do it.
If one of the keywords is entered, the variable #keyword will be set to FOUND! so you can use if defined #keyword to process from there.
It's not protected against destructive user-inputs - that's not what this question is about...
You'd be better off collecting all the questions in a document (like .html) and letting the user search that document for what they need. But if this is just an exercise, you can re-write your logic like so to make your program work:
:menu
set "c="
set /p "c=Please type your question: "
echo %c% | findstr /i /b "ringout" >nul
if errorlevel 1 goto Sorry else goto Ringingout
:Ringingout
and so on.

Problems with BAT file: IF/ELSE not working as expected

I'm trying to make a short BAT file and I'm having trouble with one of its functions. I've tried a number of different ways to do this and none of them seem to work, but being a beginner at this I can't figure out the problem. Basically, the script, as it runs, is supposed to check if a certain .BAT file exists, and if it does, the script asks if the user wants to run it. If the user indicates Y, the other BAT is called and then the original script proceeds. If the user indicates N, the script is supposed to proceed without calling the other BAT. So far the script always notices and asks about the file, but choosing Y at the prompt never works. I'm sure the solution is obvious, but it's escaping me. Here's the code:
SET /P kmname=Enter database name:
:kmstart
IF EXIST C:\Visual\area\%kmname%\%kmname%.flt (
ECHO %kmname%.flt found, will now create %kmname%.ive.
CD C:\Visual\area\%kmname%\
IF EXIST Preprocess.bat (
SET /P kmpreproc=Found Preprocess.bat. Do you want to run it now?
IF /I "%kmpreproc%" EQU "Y" (
GOTO PREPROC
) ELSE (
GOTO CONTINUE
)
)
GOTO CONTINUE
) ELSE (
ECHO C:\Visual\area\%kmname%\%kmname%.flt does not exist. Try again.
SET /P kmname=Enter database name:
GOTO kmstart
)
:PREPROC
ECHO Running Preprocess.bat.
:CONTINUE
ECHO Continuing process.
PAUSE
The problem is your variables are being evaluated before they enter the if's, which means cmd won't see any changes until they have ended.
This is causing problems for you as your variables kmpreproc and, depending on the first if result, kmname change within the if blocks.
The fix (presuming the rest of your code is working) is to enable delayed expansion and use delayed expansion instead of normal expansion, by changing the %'s to ! on your variables.
setlocal enabledelayedexpansion
SET /P kmname=Enter database name:
:kmstart
IF EXIST C:\Visual\area\!kmname!\!kmname!.flt (
ECHO !kmname!.flt found, will now create !kmname!.ive.
CD C:\Visual\area\!kmname!\
IF EXIST Preprocess.bat (
SET /P kmpreproc=Found Preprocess.bat. Do you want to run it now?
IF /I "!kmpreproc!" EQU "Y" (
GOTO PREPROC
) ELSE (
GOTO CONTINUE
)
)
GOTO CONTINUE
) ELSE (
ECHO C:\Visual\area\!kmname!\!kmname!.flt does not exist. Try again.
SET /P kmname=Enter database name:
GOTO kmstart
)
:PREPROC
ECHO Running Preprocess.bat.
:CONTINUE
ECHO Continuing process.
PAUSE
Here is below my corrected and tided up code :
#echo off
SET /P kmname=Enter database name:
:kmstart
IF EXIST C:\Visual\area\%kmname%\%kmname%.flt (
ECHO %kmname%.flt found, will now create %kmname%.ive.
CD C:\Visual\area\%kmname%\
IF EXIST Preprocess.bat (
SET /P kmpreproc=Found Preprocess.bat. Do you want to run it now?
IF /I "%kmpreproc%"=="Y" (
GOTO PREPROC
)
GOTO CONTINUE
)
)
ECHO C:\Visual\area\%kmname%\%kmname%.flt does not exist. Try again.
SET /P kmname=Enter database name:
GOTO kmstart
:PREPROC
ECHO Running Preprocess.bat.
call "cmd /c start Preprocess.bat"
pause
:CONTINUE
ECHO Continuing process.
PAUSE
If it doesn't work try writting setlocal EnableDelayedExpansion under #echo off and replacing all % with ! .

Resources