Batch file says ( was unexpected at this time during if - batch-file

So I am making a batch file that will generate a random number, keep it in a variable, and then you try to guess it. If you guess lower than the number, it will make your try counter go up by one, and tell you to guess higher, and vice versa. However, when I enter a number, it says ( was unexpected at this time. Can anyone help me?
Here is the code:
#echo off
cls
:1
setlocal EnableDelayedExpansion
set /a x = 0
set /a x = %RANDOM:~-3%
endlocal
goto 2
:2
set /p v = Enter your guess:
if %v% lss %x% (
echo Greater than that!
set /a g = %g%+1
title %g% Guesses so far!
goto 2
) else if %v% gtr %x% (
echo Less than that!
set /a g = %g%+1
title %g% Guesses so far!
goto 2
) else if %v% equ %x% (
echo Correct! It was %x%! It also took you %g% guesses to find it!
set /a g = 0
title %g% Guesses so far!
goto 1
)
echo That's not a number!
goto 2

Batch is sensitive to spaces in a SET statement. SET FLAG = N sets a variable named "FLAGSpace" to a value of "SpaceN"
consequently, v is not set up and the if is interpreted as if lss 4 (
You will also have problems with setting a variable like g within a ode block (parenthesised sequence of lines). %g% will be evaluated at parse-time - it is not interpreted as the run-time value (ie. as code controlling the block is executed)
Pleas see many SO articles on delayed expansion my using the search facility on the top bar of the page.

Your problem is:
set /a x = 0
:: make it be:
set /a x=0
No Space.

Related

Sum in batch script

How can I make the sum of the imputed numbers given by the user from the keyboard ? I tried a for loop but is endless. I cannot figure out a break statement.
::#ECHO OFF
setlocal EnableDelayedExpansion
set /p X=
SET /A suma=0
:Loop
FOR %%G IN (%X%) DO (
IF %%G GTR 0 (
SET /A suma=%suma%+%%G
)
)
SHIFT
GOTO Loop
:completed
echo %suma%
What i want to do is to make the program more user friendyl like echo somthing for the user to know it is supposed to write somthing. I know the correct code for this question, but the numbers are given as parameters in the command (syntax: script.bat parameter1 parameter2 parameter3).
::#ECHO OFF
SET /A suma=0
:Loop
IF "%1"=="" GOTO completed
FOR %%F IN (%1) DO (
IF %1 GTR 0 (
SET /A suma=%suma%+%1
)
)
SHIFT
GOTO Loop
:completed
echo %suma%
Please give me any idea for the breaking statement in the first example or how can I modify the code to take the numbers from the users imput variable and not as paramaters.
Thank you.
SET /A suma=0
set "X=%*"
if not defined X set /p "X=No parameters detected "
if not defined X ECHO No user-input detected&goto completed
FOR %%G IN (%X%) DO (
IF %%G GTR 0 (
SET /A suma=suma+%%G
)
)
:completed
echo %suma%
%* means the command-line tail. If no tail, then ask user for input. If still no data, issue message and show result.
shift moves the command line tail one position, so %2 becomes %1, etc. You haven't provided a test to exit the routine - and the command-line tail is presumably empty, so you are shifting it (which does nothing) and looping.
The for...%%G.. processes the entire list %X%, so there's no point in the shift/loop - the data has already been processed.

What is the reason for "( was unexpected at this time." on an IF command line with %var%?

When I start the batch file as posted below, I got this error
( was unexpected at this time.
I think this happens on the IF command line if %ad%==60 ( but I am not sure.
( was unexpected at this time.
#echo off
color 0f
title TITLE
mode con cols=50 lines=25
set ad = 0
set s = 0
set m = 0
set h = 0
set d = 0
if exist start.txt (
del start.txt
goto :1
) else (
exit
)
:1
if %ad%==60 (
:: Something here
set ad = 0
)
:: MINUTES
if %s%==60 (
set /a m=m+1
set s = 0
)
:: HOURS
if %m%==60 (
set /a h=h+1
set m = 0
)
:: DAYS
if %h%==24 (
set /a d=d+1
set h = 0
)
cls
echo Something here...
timeout 1 > nul
set /a ad=ad+1
set /a s=s+1
goto :1
What could be the reason for this error message on execution of the batch file?
For a start,
set ad = 60
will not set ad to 60. It will set the variable adspace to space60, leaving ad to whatever it was before the script started.
In your case, it's almost certainly an empty string because the command that would result from that would be the same as that in the following transcript (note the error generated):
d:\pax> if ==60 (
( was unexpected at this time.
If you want nicely spaced out expressions, you already know how to do that, since you used it to increment h. In other words:
set /a "ad = 0"
This isn't technically an answer, (that has already adequately been provided). It is just an example to show you how you may optionally shorten your script a little:
#Echo Off
Color 0F
Title TITLE
Mode 50,25
Set /A ad=s=m=h=d=0
If Not Exist "start.txt" Exit /B
Del "start.txt"
:1
If %ad% Equ 60 (
Rem Something here
Set "ad=0"
)
Rem Minutes
If %s% Equ 60 Set /A m+=1,s-=60
Rem Hours
If %m% Equ 60 Set /A h+=1,m-=60
Rem Days
If %h% Equ 24 Set /A d+=1,h-=24
ClS
Echo Something here...
Timeout 1 >Nul
Set /A ad+=1,s+=1
GoTo :1
Notes: 1. Using Timeout 1 will not increment clocklike (in accurate seconds), it would be approximately one second plus the time taken to run through :1 again. 2. Be careful not to fall into Set /A's octal trap, by ensuring that you don't have leading 0's in your variables.
I have IF command without spaces, and also batched with command in quotes; still got error ( was unexpected at this time. when called batch file from command line. If launched from explorer, the batch file crashed.
Here's the crash code:
if %file%==local (
set miss=n
set /p miss=Any missing?
set miss=%miss:~0,1%
if /I %miss%==y (
Goto check2
)
)
When I echo the value of miss before the IF statement, I get %miss:~0,1%
TO fix this, I enabled delayed expansion, to force values to be updated at runtime, and works ok now.
if %file%==local (
set miss=n
set /p miss=Any missing?
set miss=!miss:~0,1!
if /I !miss!==y (
Goto check2
)
)

An If statement in my .bat script isn't working as expected

What is supposed to happen is that you input a number between 1 and 1,048,567. The program checks if your input is actually a number between 1 and 1,048,567. If your input is a valid number then it will continue onto the next bit of code. If the input is invalid then it will display a message saying it is invalid then loop back and ask you for input again.
When I run this however, I input anything and it says invalid input even if I did input a number between 1 and 1,048,567.
Code:
:setup
#echo off
title Pokemon Shiny Sim
set delay = nul
set count = 0
set chance = 4096
:settings
:setChance
cls
echo Set shiny chance (1 in x). Range: (1-1,048,567)
echo Leave blank for 1 in 4096.
set /p chance = Input:
set /a chance = %chance%+0
if %chance% GEQ 1 (
if %chance% LEQ 1048567 (
goto setDelay
)
)
echo Invalid Input.
pause
goto setChance
:setDelay
cls
echo Set delay between attempts in seconds. Range: (1-60).
echo Leave blank for no delay.
set /p delay = Input:
set /a delay = %delay%+0
if %delay% == nul (
goto loopStart
)
if %delay% GEQ 1 (
if %delay% LEQ 60 (
cls
goto loopStart
)
)
echo Invalid Input.
pause
goto settings
:loopStart
set /a count = %count%+1
set /a rand = %random% %% %chance%+1
if %rand% == 1 (
echo Attempt: %count% | Shiny: Yes!
pause
)
else (
echo Attempt: %count% | Shiny: No
)
goto loopStart
I suggest to read first debugging a batch file and second the answer onWhy is no string output with 'echo %var%' after using 'set var = text' on command line?
Next look on your rewritten code below:
:setup
#echo off
title Pokemon Shiny Sim
set "delay=0"
set "count=0"
set "chance=4096"
:settings
:setChance
cls
echo Set shiny chance (1 in x). Range: (1-1,048,567)
echo Leave blank for 1 in 4096.
set /P "chance=Input: "
set /A chance+=0
if %chance% GEQ 1 if %chance% LEQ 1048567 goto setDelay
echo Invalid input.
pause
goto setChance
:setDelay
cls
echo Set delay between attempts in seconds. Range: (1-60).
echo Leave blank for no delay.
set /P "delay=Input: "
set /A delay+=0
if %delay% == 0 goto loopStart
if %delay% GEQ 1 if %delay% LEQ 60 cls & goto loopStart
echo Invalid input.
pause
goto settings
:loopStart
set /A count+=1
set /A rand=%random% %% chance + 1
if %rand% == 1 (
echo Attempt: %count% ^| Shiny: Yes!
pause
) else (
echo Attempt: %count% ^| Shiny: No
)
goto loopStart
All spaces around the equal signs are removed in this batch code.
The command line set "delay = nul" is modified to set "delay=0" because the condition if %delay% == nul is never true after execution of set /a delay = %delay%+0 resulting in execution of set /a delay = nul + 0 which results in assigning value 0 to environment variable delay on nul not existing as environment variable with that name having an integer value. The result of a valid arithmetic expression is always a number assigned as string to the environment variable and never a string like nul.
set /a chance = %chance%+0 is modified to set /A chance+=0 and set /a delay = %delay%+0 is modified to set /A delay+=0 because otherwise the input check is insecure as the user has for example the freedom to enter | for variable chance resulting in execution of command line set /a chance = |+0 which cause an unexpected exit of batch file execution.
Never use %variable% or !variable! in an arithmetic expression as not needed in general.
The help output on several pages on running set /? in a command prompt window explains in chapter about usage of set /A that each string which can't be interpreted as number or operator isĀ interpreted automatically as name of an environment variable whose current value should be converted to an integer on evaluation of the expression. If the environment variable is not defined at all or its value can't be successfully converted to a 32-bit signed integer, it is replaced in the expression by integer value 0.
There are exceptions like the usage of a random number in an arithmetic expression which requires %random% or !random! or when a variable name contains a space character or a character which would be interpreted as operator. In such cases it is necessary that the Windows command interpreter replaces the environment variable name already in preprocessing state or immediately before execution of the command set by random value respectively value of the environment variable.
set /a chance = %chance%+0 makes it also possible that the user of this batch file enters for example PROCESSOR_LEVEL or PROCESSOR_REVISION and this input although not being a number at all would be handled as valid because those two strings are the names of environment variables having numbers as values. PROCESSOR_REVISION has by default a hexadecimal number assigned which can be processed nevertheless completely or partly as number by command set.
Another syntax error is in block
if %rand% == 1 (
echo Attempt: %count% | Shiny: Yes!
pause
)
else (
echo Attempt: %count% | Shiny: No
)
The keyword else must be on same line as the closing ) of true branch of the IF condition separated from ) with a space character.
And redirection operator | must be escaped with caret character ^ to be interpreted as literal character to output into console window.
Note: set /A chance+=0 makes it still possible to enter for example 170 percent or 170X which results in chance having value 170 and therefore input is valid although in real the entered string is not a number.
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.
cls /?
echo /?
goto /?
if /?
pause /?
set /?
title /?
I haven't tested the code yet, but I found some fatal issues in the code.
Mis-setting variable
set /a count = %count% + 1
This sets a variable count (Note the space!). Remove the space! Also, this can be shortened to set /a count+=1.
ECHOing special characters
| is one of the special characters reserved for redirection in batch. To properly echo it, use echo string ^| string instead.
Poor IF statement practice
if %rand% == 1 (
only works when %rand% is alphanumeric. If %rand% is space, the cmd.exe sees:
if == 1 (
which is incorrect.
To correct it, do
if "%rand%"=="1" (
Alternatively, use EQU for numeric comparison, and == for string comparison.

Why are mathematical operations and output of environment variables in an ELSE branch not working as expected?

I am trying to use nested if-else statements in order to implement or operator.
The problem is that the code only works outside the last nested else statement and I can't figure out why.
I added some notes marked with // that are not actually in the script to help you get a clue of what I am trying to do.
Here is my batch script:
:computerMakePick
setLocal
set /a currentNumber= 15
set /a addOne=%currentNumber%+1
set /a addTwo=%currentNumber%+2
//the next segment implements OR operator for two conditions using nested if-else statement
if %addOne% == 7 ( //checking first condition.
echo Computer chose: %addOne%
set /a currentNumber= %addOne%
)else (
if %addTwo% == 8 ( // now checking: OR second condition
echo Computer chose: %addTwo%
set /a currentNumber= %addTwo%
)else ( // if not both of the above then do this. NOW this section below doesn't work
set /a bottomlimit= 1
set /a upperlimit= 2
set /a limit=%upperlimit%-%bottomlimit%+1
set /a randomChoice= %bottomlimit% + %RANDOM% %% %limit%
set /a currentNumber= %currentNumber%+%randomChoice%
echo Computer chose: %currentNumber%
)
)
endLocal & set /a currentNumber= %currentNumber%
goto :eof
If I take the last else section to outside like this below, then it works:
:computerMakePick
setLocal
set /a currentNumber= 15
set /a addOne=%currentNumber%+1
set /a addTwo=%currentNumber%+2
//the next segment implements OR operator for two conditions using nested if-else statement
if %addOne% == 7 ( //checking first condition.
echo Computer chose: %addOne%
set /a currentNumber= %addOne%
)else (
if %addTwo% == 8 ( // now checking: OR second condition
echo Computer chose: %addTwo%
set /a currentNumber= %addTwo%
)else (
echo. // need to put something in here or else it doesn't work.
) // could also delete this last else-statment but it doesn't matter
)
//now this below works fine. and I don't understand why under second-else section it doesn't
set /a bottomlimit= 1
set /a upperlimit= 2
set /a limit=%upperlimit%-%bottomlimit%+1
set /a randomChoice= %bottomlimit% + %RANDOM% %% %limit%
set /a currentNumber= %currentNumber%+%randomChoice%
echo Computer chose: %currentNumber%
endLocal & set /a currentNumber= %currentNumber%
goto :eof
By saying it's not working I mean if I print the values of each variable: bottomlimit, upperlimit, limit, etc. when they are defined inside the second else statement, for example for the command line echo value of limit is = %limit% I get blanks (nothing).
Why is this happening and how can I fix it to work inside the second else statement?
Use the following code:
#echo off
:computerMakePick
setLocal
set "currentNumber=15"
set /a addOne=currentNumber + 1
set /a addTwo=currentNumber + 2
rem // the next segment implements OR operator for two conditions using nested if-else statement
if %addOne% == 7 ( rem // checking first condition.
echo Computer chose: %addOne%
set "currentNumber=%addOne%"
) else if %addTwo% == 8 ( rem // now checking: OR second condition
echo Computer chose: %addTwo%
set "currentNumber=%addTwo%"
) else ( rem // if not both of the above then do this. NOW this section below doesn't work
set "bottomlimit=1"
set "upperlimit=2"
set /a limit=upperlimit - bottomlimit + 1
set /a randomChoice=bottomlimit + %RANDOM% %% limit
set /a currentNumber+=randomChoice
setlocal EnableDelayedExpansion
echo Computer chose: !currentNumber!
endlocal
)
endLocal & set "currentNumber=%currentNumber%"
goto :EOF
Environment variables are always of type string. So even on using integers, the numbers are stored in memory as strings and not as integers. Therefore don't use set /a variable=number if there is no real reason to do so as this results in converting number from string to integer for the arithmetic expression, and converting it back from integer to string for assigning the result of this arithmetic expression to environment variable.
Usage of environment variable expansion within an arithmetic expression which is the string after set /a is usually nonsense as Windows command interpreter automatically interprets each string not being a number or an operator as name of an environment variable whose current value has to be converted to an integer for evaluation of the expression.
Yes, whether immediate nor delayed expansion is needed within an arithmetic expression even when the set /a command line is within a command block.
And in batch files // is not a comment, use command REM and take into account that Windows command interpreter first parses the lines with command REM and then executes the command if there is no syntax error, see %~ in REM statement.
For more details:
Run in a command prompt window set /? and really read carefully everything of output help.
If you use any of the logical or modulus operators, you will need to
enclose the expression string in quotes. Any non-numeric strings in the
expression are treated as environment variable names whose values are
converted to numbers before using them. If an environment variable name
is specified but is not defined in the current environment, then a value
of zero is used. This allows you to do arithmetic with environment
variable values without having to type all those % signs to get their
values.
Read the answer Why is no string output with 'echo %var%' after using 'set var = text' on command line?
Read the answer on IF ELSE syntax error within batch file?
Variables within the else-statement are not expanded. Use setlocal enabledelayedexpansion instead and denote your variables with exclamation marks:
:computerMakePick
setLocal enabledelayedexpansion
set /a currentNumber= 15
set /a addOne=%currentNumber%+1
set /a addTwo=%currentNumber%+2
if %addOne% == 7 (
echo Computer chose: %addOne%
set /a currentNumber= %addOne%
)else (
if %addTwo% == 8 (
echo Computer chose: %addTwo%
set /a currentNumber= %addTwo%
)else (
set /a bottomlimit= 1
set /a upperlimit= 2
set /a limit=!upperlimit!-!bottomlimit!+1
set /a randomChoice= !bottomlimit! + !RANDOM! %% !limit!
set /a currentNumber= !currentNumber!+!randomChoice!
echo Computer chose: !currentNumber!
)
)
endLocal & set /a currentNumber= %currentNumber%
goto :eof

What's wrong with this "Guess my number" batch game?

I wrote this game. it simply sets a random number between 1 and 16 and the user must guess it. when the guess was correct, it shows the attempt count to the user.
But when I run it and enter a number, it displays an error and the close immediately. I think the error says missing something.
#echo off
color 0A
set /a key = %random% / 2048
set /a attempts=0
title Guess My Number (0 to 16)
:AGAIN
set /p in = Guess it.
set /a in = %in%
if %key% GTR %in% (
echo My Number is greater.
set /a attempts=%attempts%+1
goto again
)
if %key% LSS %in% (
echo My Number is less.
set /a attempts=%attempts%+1
goto again
)
if %key% == %in% (
echo right!
echo You Guessed it in %attempts% attempts.
goto end
)
:end
pause
As npocmaka wrote, the error is that you have spacec in your SET statements. Removing them results in the following code which works perfectly:
#echo off
color 0A
set /a key =%random% / 2048
set /a attempts=0
title Guess My Number (0 to 16)
:AGAIN
set /p in=Guess it.
set /a in=%in%
if %key% GTR %in% (
echo My Number is greater.
set /a attempts=%attempts%+1
goto again
)
if %key% LSS %in% (
echo My Number is less.
set /a attempts=%attempts%+1
goto again
)
if %key%==%in% (
echo right!
echo You Guessed it in %attempts% attempts.
goto end
)
:end
pause
EDIT: And by the way, your code is nonsense. The answer is always 2. :D I guess you need something like set /a key=%random%%%16
Here's how I'd do your little game
#echo off
color 0A
title Guess My Number (0 to 16)
:Start
set /a key=%random%%%16
set attempts=0
:again
set /p in=What is your guess? (0-16):
set /a attempts+=1
if %key% GTR %in% (
echo My Number is greater.
goto again
)
if %key% LSS %in% (
echo My Number is less.
goto again
)
if %key% == %in% (
echo CORRECT!
echo You Guessed it in %attempts% attempts.
pause
)
Your issue is already solved, with the extra spaces. But I used a different method to generate a random number up to 16, and I moved your attempts counter up to just below the set /p so it'll always be counting up one. In your current version, you have it set to only go up for incorrect guesses. I think it should count the final guess as well. Plus I shortened the attempts counter slightly for you, just a helpful tip for you in the future.
-Edit- I forgot to mention, you don't need this line at all set /a in=%in% as the variable %in% is already set with this line set /p in=Guess it. there's no need to set it twice.

Resources