can someone please tell me how can I make a batch file the inputs 5 numbers and checks for each number if its even ir odd? i dont know what i did wrong about the module part:
#echo off
for /l %%i IN (1,1,5) DO (
set /p num1=
set /a "mod=%num1% %% 2"
echo mod=%mod%
if mod EQU 0 (echo EVEN!)else echo ODD!
echo.
)
echo 5 numbers were inputed.
echo.
pause
and another question: Can I not declare the num1 variable and check if its even inside the if (having a mathematical expression inside the if and not only a simple comparison)?
thanks :)
You cannot do mathematical computations within an IF statement.
Here are some problems with your code:
Normal expansion occurs when a statement is parsed, and all code within your FOR loop is parsed in one pass. So %mod% expands to a constant value - the value that existed before the FOR loop begain (or empty string if mod was not defined).
Variables must be expanded if you want to use them in an IF statement.
Not a bug - but numeric variables do not need to be expanded to use them in a SET /A statement.
Here is one solution - have the loop call a subroutine that gets reparsed each iteration:
#echo off
setlocal
for /l %%i in (1,1,5) do call :test
echo 5 numbers were inputed.
echo(
pause
exit /b
:test
set /p "num1=Enter a number: "
set /a "mod=num1 %% 2"
echo mod=%mod%
if %mod% EQU 0 (echo EVEN!)else echo ODD!
echo(
Another option is to enable and use delayed expansion. Unquoted ! literals must be escaped as ^^! if delayed expansion is enabled. Not needed here, but a quoted ! would be escaped as "^!"
#echo off
setlocal enableDelayedExpansion
for /l %%i in (1,1,5) do (
set /p "num1=Enter a number: "
set /a "mod=num1 %% 2"
echo mod=!mod!
if !mod! EQU 0 (echo EVEN^^!)else echo ODD^^!
echo(
)
echo 5 numbers were inputed.
echo(
pause
exit /b
If you do not need to print out the mod value, you can use a math trick to avoid use of CALL or delayed expansion. You can divide by the mod value, and it will raise an error if mod is 0. You can conditionally take action using && for success (odd) and || for failure (even).
#echo off
for /l %%i in (1,1,5) do (
set /p "num1=Enter a number: "
set /a "1/(num1 %% 2)" 2>nul &&echo ODD!||ECHO EVEN!
echo(
)
echo 5 numbers were inputed.
echo(
pause
exit /b
Related
Forgive me if there is a simple answer to this, I'm new to all of this.
The below .bat script generates a list of numbers depending on how many numbers you want.
However what I would like is to format the numbers it generate.
For example, if I input 20, instead of it coming out 1, 2, 3 etc. I would like it to come out as 001, 002... 020.
Is this possible? Am I missing something obvious?
Many Thanks.
#echo off
setlocal EnableExtensions
:start
cls
set /p loopcount= How Many Users?:
set "x="0"
:loop
set /a "x+=1"
echo %x%
set /a loopcount=loopcount-1
if %loopcount%==0 goto exitloop
goto loop
:exitloop
pause
goto start
just implementing SomethingDark's suggestion (and a minor change in the logic of the loop):
set /p "loopcount= How Many Users?: "
set "x=1000"
:loop
set /a x+=1
echo %x:~-3%
set /a loopcount-=1
if %loopcount% gtr 0 goto :loop
echo loop finished.
(btw: your set "x="0" has a quote too much (probably a typo)
Here's a quick example batch file which uses powershell for your leading zeroes.
I have used a for loop as the looping mechanism.
#Echo Off
SetLocal EnableExtensions
:AskNum
Set "num=1"
Set /P "num=how many users?"
Set num | findstr.exe /RX "^num=[123456789][0123456789]*$" 1>NUL || GoTo AskNum
For /F %%G In ('powershell.exe "1..%num% | %% ToString User000"') Do Echo %%G
Pause
This script will not continue unless the end user inputs an integer, without a leading 0, and which is a minimum value of 1. Here you can modify the Echo command in Do to an alternative, for example net.exe User %%G /Add, or if you wish, to a parenthesized sequence of commands. In each case %%G will contain the returned string with the incremented three digits.This version prepends each three digit number sequence with an additional string, (User), but that can simply be deleted or replaced if/as required.
#ECHO OFF
SETLOCAL enabledelayedexpansion
SET /p "lastnum= How many numbers? "
SET /a lastnum+=1000
FOR /L %%e IN (1001,1,%lastnum%) DO SET /a num=%%e&ECHO !num:~-3!
GOTO :EOF
No need for complication
I'm making a small little game I want a random chance to get certain items (e.g. if the random number is greater than 10 but less than 15 then you will get a certain item). Here's what I've already tried which resulted in a crash.
set /a chance= %random% %%30+1
if %chance% gtr 10 && lss 30 (
set /a %nails%+1
echo You got nails! %chance%
)
This piece right here was just a test, but should give you an idea of what I am going for. This is really the only way I can think of doing it. If you could help, please do! :)
I see a number of problems in that code:
set /a chance= %random% %%30+1
if %chance% gtr 10 && lss 30 (
set /a %nails%+1
echo You got nails! %chance%
)
Going through them:
The if statement is not valid, && is the "execute next command if previous command worked" conjunction, not a general "and" operator. To do what you want would be:if %chance% gtr 10 if %chance% lss 30.See here for a way to do and and or in cmd language.
The command set /a %nails%+1 does not actually change nails in any way, it just evaluates an expression and throws it away. You need an assignment to assign a value, and you don't need the variable markers in this case:set /a "nails += 1".
If you're using delayedexpansion to print out nails (and you should be), you need a ! both before and after the variable name:echo You got !nails! %chance%.
As an aside, you'll probably notice I have a penchant for quoting my set /a expressions and spacing them nicely - I find this aids readability.
That will fix some specific problems but, to be honest, you're probably better off making a generic function that can give you a yes/no answer for some probability of an event happening. That way, you can reuse it anywhere you need it.
You can use a function like chance, shown below in a complete program, to decide whether something should happen based on a percentage:
#echo off
goto :main
:chance
setlocal enableextensions enabledelayedexpansion
set retcode=1==0
set /a "value = %random% %% 100"
rem echo %value% rem uncomment for debugging
if %value% lss %2 set retcode=1==1
endlocal && set %1=%retcode%
goto :eof
:main
call :chance result 50
echo %result%
It should be called with both a variable name to put the result into, and the percentage level you want to use. For example, if you wanted to set a variable hasdied based on a 5% chance, you would call it with:
call :chance hasdied 5
if %hasdied% goto :handlebeingdead
The function contains a number of features which probably bear explanation:
The setlocal command ensures that no variables escape the scope of this function (but see below), useful for proper encapsulation.
The value variable is set to some random value between 0 and 99 inclusive. It's not perfectly distributed since %random% will give you a value up to 32767 so will be slightly skewed toward numbers less than 68. Said skew is probably not enough to concern yourself with.
This value is then compared with the threshold you provided (the second argument) to decide the return value true or false.
The return value is rather sneaky in that it gives you an expression that you can put into an if statement without having to do an explicit comparison like:if %hasdied%==1By returning such an equality comparison directly, you can just use the return value as if it was boolean.
The endlocal then cleans up any variable changes that have been made in this function, including the return code. However, the fact that the substitutions on this line take place before any of it is executed means that the set part of it will already have the correct value of retcode substituted before the endlocal cleans it up. This is a way to have specific variables "escape" the scope bounded by setlocal/endlocal. The retcode value is therefor placed in the parameter whose name you provided as the first argument.
The set %1= part of that command is a way to allow you to specify what variable should receive the value in the call itself, akin to myvar = function(). That stops you from having to allocate a hard-coded variable name to each function and then assign it to another variable after the call.
And, of course, the goto :eof is simply a return instruction.
I'm pretty sure the && does not exist in batch. Nested if statements work:
set /a chance= %random% %%30+1
echo %chance%
IF %chance% GTR 10 (IF %chance% LSS 15 (
echo You got nails! %chance%
))
You cannot use && like that. You need to run the if statement twice to match both gtr and lss you can put them one after the other:
#echo off
set /a chance=%random% %%30+1
if %chance% gtr 10 if %chance% lss 30 (
set /a nails+=1
echo You got nails! %chance%
)
Also note the correct way of increasing a variable set /a nails+=1
the if condition approach works and all, but is somewhat clunky if your going to be scripting in many loot situations. it is by far easier to use an array setup with a macro that can access ranges within the array to allow you to simply and easily script loot boxes that roll different items by using substring modification to change the index of the array the random number can access. a demonstration:
#Echo off
:new
::: -------------------------------------------------------------------|| MACRO DEFINITIONS
Setlocal DisableDelayedExpansion
(Set \n=^^^
%=DNR=%
)
rem ********************* Display any existing character names for continuation or deletion of characters
If Exist "%TEMP%\%~n0_*_save.bat" (Echo/Your Characters:&Echo/&(For /F "Delims=" %%G in ('Dir "%TEMP%\%~n0_*_save.bat" /B')Do For /F "Tokens=2 Delims=_" %%o in ("%%~nG") Do < Nul Set /P "=[%%o] ")&Echo/)
:character
Set /P "Name=Name: "
If Exist "%TEMP%\%~n0_%Name%_save.bat" (Echo/[C]ontinue / [D]elete?&For /F "Delims=" %%O in ('Choice /N /C:cd')Do If /I "%%O"=="C" (Goto :playon)Else (Del /P "%TEMP%\%~n0_%Name%_save.bat" & Goto :character))
If "%Name%"=="" Goto :character
:playon
rem *** Inventory Macro. Displays all elements for the given group and their current values.
rem ::: Usage: %INV:#=$varname[%
Set "INV=Echo/&(For /F "Tokens=2 Delims==" %%i in ('Set #') Do (Set "VN=%%i"&^< Nul Set /P"=[!VN:$=!:!%%i!] "))&Echo/"
rem *** Autosave macro. Can be incorperated into other macro's
rem ::: Usage: %Save%
Set SAVE=(For /F "Tokens=1 Delims==" %%i in ('Set $') Do (If not "!%%i!"=="" Echo/Set "%%i=!%%i!"))^>"%TEMP%\%~n0_!name!_save.bat"
rem *** Location Display Macro with autosave macro included
rem ::: Usage: %Loc:#=LocationLABEL%
Set "Loc=(Set "$Loc=#"&Title !$Loc:_= !)&%Save%"
rem *** Loot box Macro to generate random loot from specified range of an indexed array
rem *** !random! %%4 + Index# will access an index range between the index # and 4 above the index number.
rem ::: Usage: %Loot:#=index#%
Set "LOOT=(For /F "UsebackQ Delims=" %%i in (`"Set /A i#=!Random! %%4 + #"`) Do For /F "UsebackQ Delims=" %%v in (`"Set /A v#=!Random! %%3 + 1"`) Do (Set "VN=!$Loot[%%i]:$=!"&Echo/You got %%v !VN!&Set /A "!$Loot[%%i]!+=%%v")) 2> Nul & %SAVE%"
rem *** the below macros /I /V and /P are not used in this example. - They are an optional method for defining
rem *** variables prefixed with $ that automatically saves them for reloading
rem ::: usage: %/I:V=Varname%Input Prompt String:
Set "/I=For %%n in (1 2)Do If %%n==2 (Set /P "$V=!$PromptStr:$=!: "&%Save%)Else Set $PromptStr="
rem ::: usage: %/P:V=Varname%VariableValue
Set "/V=For %%n in (1 2)Do If %%n==2 (Set "$V=!str!"&%Save%)Else Set str="
rem ::: usage: %/A:V=Varname%=Equation
Set "/A=For %%n in (1 2)Do If %%n==2 (Set /A "$V!sum!"&%Save%)Else Set sum="
rem *** Wait prompt Macro
rem ::: usage: %Wait:#=Integer value for time in seconds%Wait Prompt String
Set "Wait=For %%n in (1 2)Do If %%n==2 (Timeout # /Nobreak > Nul & (Pause | Echo/!Output!) 2> Nul )Else Set Output="
rem *** Array definition macro. Asigns the element names to an indexed Groupname (Array), With each element being assigned an initial 0 value
Rem ::: Usage: %DefArray%{VarGroupName}{Element names as list}
Set DefArray=For %%n in (1 2) Do if %%n==2 (%\n%
Set "i#=0"%\n%
For /F "Tokens=1,2 Delims={}" %%G in ("!List!") Do (%\n%
For %%i in (%%~H) Do (%\n%
Set "$%%~G[!i#!]=$%%i"%\n%
Set "$%%i=0"%\n%
Set /A i#+=1 ^> Nul%\n%
)%\n%
)%\n%
) Else Set List=
Set Menu=CLS^&Set "Copt="^&For %%n in (1 2) Do if %%n==2 (%\n%
Echo/[E]xit%\n%
For %%G in (!OPTS!)Do (%\n%
Set "opt=#%%~G"%\n%
Set "opt=!opt:_= !"^&Set "Opt=!Opt:~,-1!"%\n%
Set "Copt=!Copt!%%~G"%\n%
Echo/!Opt! [%%~G]%\n%
)%\n%
(For /F "Delims=" %%O in ('Choice /N /C !Copt!E')Do If "%%O"=="E" (Endlocal^&Endlocal^&Set "Name="^&Goto :New) Else (CLS^&Goto :#%%O))%\n%
) Else Set OPTS=
::: -------------------------------------------------------------------|| END MACRO DEFINITIONS
::: -------------------------------------------------------------------|| Example Script
REM // required to be enabled PRIOR to macro Use, AFTER definition.
Setlocal EnableDelayedExpansion
%DefArray%{Loot}{Wood Nails Ore Leather Gold Silver Bronze Jade}
IF Exist "%TEMP%\%~n0_!name!_save.bat" (
Call "%TEMP%\%~n0_!name!_save.bat"
Goto :!$Loc!
)
:Menu
%Loc:#=Menu%
%Menu:#=Loot_Box_% "1" "2"
Goto :Menu
:Loot_Box_1
%Loc:#=Loot_Box_1%
%Loot:#=0%
%INV:#=$Loot[%
%Wait:#=1%
Goto :Menu
:Loot_Box_2
%Loc:#=Loot_Box_2%
%Loot:#=4%
%INV:#=$Loot[%
%Wait:#=1%Demo wait prompt
Goto :Menu
Why does this batch code not work?
I certainly don't know why...
Download: http://tufda.net/downloads/explore/StackOverflow%20files/ultraworld.bat
#echo on
cls
set game=UltraWorld
echo Welcome to %game%!
PAUSE
cls
echo What's your name?:
set /p playername=""
cls
echo Welcome to %game%, %playername%!
PAUSE
:titlescreen
cls
echo Commands:
echo new
echo load
echo credits
echo.
set /p command1=Enter your command here:
IF command1==new (
set /p gamesave1=What name will you give this save?
)
IF command1==load (
echo No.
PAUSE
goto titlescreen
)
IF command1=="credits" (echo Everything - tufda & PAUSE & goto titlescreen)
PAUSE
When you test the variable, you need to either surround it in percentage marks, or surround it with exclamation marks, if
setlocal enabledelayedexpansion
is used.
For example,
IF %command1%==load (
When using the IF command in a batch file, you need to follow the proper syntax.
The correct way to write an IF command is:
IF /I "%command1%" EQU "new" (
The Quotes arround each side will account for an empty value, while the EQU is the comarison type which is equivelant to ==. The comparisons are as follows:
EQU - equal
NEQ - not equal
LSS - less than
LEQ - less than or equal
GTR - greater than
GEQ - greater than or equal
I used a /I to indicate that the comparison is not case sensitive.
I've recently written a password script in batch. Basically it takes the password from a different batch script, finds out how many characters it has, takes the password from the user and compares them. However, nothing is ever simple with me and I've gotten into some nested FOR loops and such. It's hard to explain, so here's the code:
#echo off
setlocal enabledelayedexpansion
call pass.bat & rem Sets the variable "pass" as "default".
set map=abcdefghijklmnopqrstuvwxyz
set len=0
for /l %%A in (12,-1,0) do (
set /a "len|=1<<%%A"
for %%B in (!len!) do if "!pass:~%%B,1!"=="" set /a "len&=~1<<%%A"
)
for /l %%C in (1,1,100) do (
set letter%%C=!pass:~%%C,1!
)
:pass
for /l %%D in (0,1,%len%) do (
cls
choice /c "abcdefghijklmnopqrstuvwxyz" /n /m "Password: !ast!"
set /a charerr=!errorlevel!-1
for /l %%E in (0,1,25) do (
set password=!password!%map:~!charerr!,1% & rem This is the problem line.
)
set ast=!ast!*
)
if "%pass%" neq "%password%" goto fail
cls
echo Correct Password
echo pass: %pass%
echo password: %password%
>nul pause
exit
:fail
set /a tries-=1
if %tries% geq 1 goto pass
Now, the script doesn't crash or anything like that, however it does not set password as the password you entered.
If you run it you'll understand.
Note: pass.bat purely contains the line set pass=default
You could try
call set "password=!password!%%map:~!charerr!,1%%"
Your variant can't work, as percent expansions are expanded when a block is parsed, so the %map:~!charerr!,1% will be expanded, but fails as !charerr! isn't expanded at that time.
The CALL can start a second parse time when evaluating the line and the double percent will then expand correct.
Posting part of the code which am looking for a workaround
if 09 LSS 9 (ECHO YES) ELSE (ECHO NO)
This command always echo's 'Yes' as it considers 09 to be less than 9. Any alternative for this command?
EDIT:
Thanks but the Modulo part is not working in the command i am trying to insert in.
Have a file test.txt which contains "1234 09" below is my command
set actualdate=9
for /f "usebackq Tokens=1,2,3" %%d in (test.txt) do (SET /a x=1000%%e %% 1000 & if %x% LSS %ActualDate% ECHO %%d >> test2.txt)
The problem with your code snippet is the syntax and also the percent expansion.
You can use & for multiple commands in one line (not the pipe |) or split them into multiple lines.
You can't access the variable x with percent expansion inside of a block, but delayed expansion works there
setlocal EnableDelayedExpansion
set actualdate=9
for /f "usebackq Tokens=1,2,3" %%d in (test.txt) do (
SET /a x=1000%%e %% 1000
if !x! LSS %ActualDate% ECHO %%d >> test2.txt
)
If you can put your numbers into variables, you can strip off the leading zero using modulo.
Try this sample:
#ECHO OFF
SET a=09
SET b=9
SET /a x=1000%a% %% 1000
ECHO %x%
SET /a y=1000%b% %% 1000
ECHO %y%
if %x% LSS %y% (ECHO YES) ELSE (ECHO NO)
PAUSE
If you try to do SET /a a=09, you'll get the following error:
Invalid number. Numeric constants are either decimal (17), hexadecimal (0x11) or octal (021).