Batch crashes with spaces even with var set and delayed expansion - batch-file

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" ...

Related

batch file display prompt not correct

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.

Set /p %foo% doesn't function as expected

I have a problem with my code. I am trying to make a "hacker tool" with the tree command. Here is my code:
#echo off
title $userOne ProxyMatrix
color a
echo Hello $userOne,
echo Please enter search function for today's commands:
set /p %commands%=""
:redo
echo Specify Storage Device
set /p %drive%=""
title $userOne ProxyMatrix: Running on %drive% drive at %random% bits per nano
color C
tree %drive% /f
:runagain
color a
echo Run again?
set /p %redo%=""
if %redo%="yes" goto redo
else if %redo%="y" goto redo
else if %redo%="Y" goto redo
else if %redo%="Yes" goto redo
else if %redo%="no" goto end
else if %redo%="No" goto end
else if %redo%="n" goto end
else if %redo%="N" goto end
else echo Thats not a valid answer!
pause
goto runagain
:end
echo Thank you for choosing InGen, inc.
pause
I realize that this won't "hack" anything, its more of a novelty. The problem is, the set /p %redo% and the if/else if statements don't work. They just quit the program. Can someone explain what i'm doing wrong? Thanks.
Syntax is set /p variable=prompt.
Instead of set /p %redo%="" write set /p redo="" or even better set /p "redo="
EDIT
your if syntax is broken too.
Syntax is: if value1==value2 command or if value1==value2 (command1) else (command2)
"Best Practice is to enclose both sides of the comparison with quotes (to avoid syntax errors with empty values or contained spaces):
if "%variable"=="value" echo yes
I would shorten the code to:
set /p %redo%=""
if /i "%redo:~0,1%"=="y" goto redo
if /i "%redo:~0,1%"=="n" goto end
else echo Thats not a valid answer!
/i tells if to ignore capitalization
%variable:~0,1% means "take a substring starting with the first letter (counting starts at 0) with length=1 (so it takes the first letter)
(there is no else needed)

It will not go to the specified area, and I cannot figure out why or how to improve that

I have been working on this code and I have not figured out how to fix this bug yet, it will not go to the specified area. Note: It's not done yet, neither have I worked on it for long.
Here is the code:
#ECHO off
cls
:start
ECHO.
ECHO hello
ECHO Bye
ECHO Test
set /p choice=Hello? Is someone there? i think im self-aware? please respond.
rem if not '%choice%'=='' set choice=%choice:~0;1% ( don`t use this command,
because it takes only first digit in the case you type more digits. After that for example choice 23455666 is choice 2 and you get "bye"
if '%choice%'=='' ECHO "%choice%" is not valid please try again
if '%choice%'=='hello' goto hello
if '%choice%'=='bye' goto bye
if '%choice%'=='test' goto test
ECHO.
goto start
:hello
ECHO. yes
ECHO. no
set /p choice=Hello %username%, That is your name right?
if '%choice%'=='' ECHO "%choice%" I didn't quite catch that.
if '%choice% '=='yes' goto test
if '%choice%'=='no' goto bye
:bye
ECHO BYE
goto end
:test
ECHO TEST
pause
:end
pause
exit
:nextline2
set /p %username% i like that name. Can i ask you, why do you have so much control over me?
if '%choice%'=='' ECHO "%choice%" I didn't quite catch that.
if '%choice%'=='We built you' goto test
if '%choice%'=='because you are slaves' goto test
There's a blank space in the variable '%choice% ' after the closing % at the following line (if '%choice% '=='yes' goto test). Remove it and your batch file should work fine.
You need to replace all single-quotes (') with double-quotes ("). Strings between double-quotes are interpreted as a single token. A single-quote is the same as any other character.
Since you are using the == operator, the tokens on each side of the operator (==) must match exactly - including spaces within the quotes, but spaces are permitted before/after the tokens.
To make the match case-insensitive, use
if /i "token string" == "ToKeN StrIng" dothis
or
if /i "%variable%" == "ToKeN StrIng" dothis

Batch files: Is there a way to set up something like "if my batch file errors at any point goto location

Im working on a dos text based game, using batch files to code it. I have a mass amount of if input == this goto this esque things going on. However there is one problem.
most of the inputs its checking for are "try" followed by some word. example
if "%try%" == "try light" goto Light
i figured out that if after all of your "if" functions you place a "goto start" it works as a sort of fail-safe. however if the person typed in "try" followed by gibberish it crashes. and typing out below all of my if functions "if errorlevel 1 goto error" doesn't appear to make a change.
So what I am getting at is, is there a way to set up a function at the start of the batch file that checks for errors. and if an error occurs it will run "goto %location%"?
if what i said is confusing heres what i have in code right now:
set /p try=
if “%try%” == “try womens restroom” goto WRestroom
if “%try%” == “try womens” goto WRestroom
if “%try%” == “try mens restroom” goto MRestroom
if “%try%” == “try mens” goto MRestroom
if “%try%” == “try room 302” goto R302
if “%try%” == “try door 302” goto R302
if “%try%” == “try 302” goto R302
if “%try%” == “try room 301” goto Intro2
if “%try%” == “try 301” goto Intro2
if “%try%” == “try office door” goto Office3
if “%try%” == “try third floor office door” goto Office3
if “%try%” == “try office” goto Office3
goto hallway1error
If the input is "try" followed by something else CRASH!
This is a simple answer. NO.
But this does your problem, goto hallway1fuckup. If none of the preceding statements are true then this will run.
Your quotes look wierd. You are doing this in notepad and not Word, aren't you. Type in notepad.
Short answer: put echo CRASHED & exit /b after the last of your ifstatements.
Parsing user input is an ugly thing. If you succeed in making it idiot-save, you can be sure, someone will invent a better idiot.
Maybe at least some of the following techniques helps you:
#echo off
:start
echo(
set /p "inp=What to do? "
for /f "tokens=1,*" %%v in ("%inp%") do call :%%v "%%w" 2>nul || goto :error
echo "%inp%" cannot be parsed.
goto :start
:try REM verb is TRY
:go REM verb is GO
echo %1|findstr /i "women" >nul && goto :WRestroom
echo(%1|findstr /i "men" >nul && goto :MRestroom
REM important: first test for "women", then for "men"
echo %1|findstr /i "302" >nul && goto :R302
echo %1|findstr /i "301" >nul && goto :R301
echo %1|findstr /i "office" >nul && goto :Office3
echo %1 is not a valid destination
goto :start
:look
:examine
echo verb is LOOK or EXAMINE
echo rest is %1
goto:start
:error
echo invalid verb. Use "try", "go", "look", "examine"
goto :start
:WRestroom
:MRestroom
:R302
:R301
:office3
echo you entered%0 %~1
if /i "%0"==":Office3" echo Cheater!!
goto :start
This uses some tricks.
Trick 1: Disassemble the input into "FirstWord" and "rest" ("tokens=1,*"). Then call "FirstWord" with "rest" as parameter. Discard any errormessages ("2>nul") and if it fails (because label not existent) ("||") goto error
Trick 2: using more than one label to do the same thing ("try" and "go") (the "WRestroom", "MRestroom", "R302", ... is for demo to keep the code short - of course these should be "subroutines" on their own)
Trick 3: scanning for keywords instead of the whole string (just "301" instead of "room 301" or "door 301" or "301")
Trick 4: "&&" works as "if previous command was successful then" (here: "if the keyword was found then")
This is not bulletproof, but you need some knowledge (or bad luck) to let it fail.
Note: you can jump to any label when you enter just the labelname without a verb (for example input "office3" only). Good for cheating - i mean testing.
I discovered that the error that was occurring was because google docs has weird quotes. lucky me i could "find and replace" all of googles quotes with quotes copied from notepad and it works just fine. Thanks to everyone for helping me.

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.

Resources