I need some help in a Batch script please - batch-file

I made a game menu and the "2" works gret but when i click "5" it adds +1 to "menumark"
BTW I have Windows 7.
Some more questions:
1) Can you put a color to a specific letter?
2) Why doesnt: if errorlevel 3 set /a menumark=%menumark%-1 work?
Code:
...
...
...
set menumark=1
set checkmark=1
set mark1=/
set mark2=.
set mark3=.
...
...
...
:MENU
cls
echo ----------
echo %mark1% (1) Play.
echo %mark2% (2) Settings.
echo %mark3% (3) Scores.
echo ----------
choice /c 25 /n
if errorlevel 1 set /a menumark=%menumark%+1
if errorlevel 2 set checkmark=2
if %menumark%==4 set menumark=1
if %menumark%==0 set menumark=1
if %menumark%==1 set mark1=/&set mark2=.&set mark3=.
if %menumark%==2 set mark2=/&set mark1=.&set mark3=.
if %menumark%==3 set mark3=/&set mark2=.&set mark1=.
if %checkmark%==2 if %menumark%==1 goto TOP
if %checkmark%==2 if %menumark%==2 goto SETTINGS
if %checkmark%==2 if %menumark%==3 goto HIGHSCORE
goto MENU
...
...
...

Your problem is the control of errorlevel. The code if errorlevel n command will execute the indicated command for any errorlevel value greater or equal to n. For this reason, to use this kind of testing it is necessary to test from greater to lower values of errorlevel and properly code to avoid problems
if errorlevel 3 echo 3
if errorlevel 2 echo 2
if errorlevel 1 echo 1
if your errorlevel is 3, the previous code will echo the three values, as all the conditions are evaluated to true.
if errorlevel 3 (
echo 3
) else if errorlevel 2 (
echo 2
) else if errorlevel 1 (
echo 1
) else echo no error level
if %errorlevel%==3 echo 3
if %errorlevel%==2 echo 2
if %errorlevel%==1 echo 1
Both versions will avoid the "problem" (or you can use gotos to avoid falling through the options)
For the color management, here you can find all the required information.

Related

is there any way to don't have to check every state between 2 numbers in batch?

i was creating a rock paper siscors game in batch, i finisced and i wanted to "clean it", becouse it checked every possible combination between the 3 numbers rappresenting rock paper siscors, but i don't know what to do
at first i tried, instead of checking every equal number, i used the "equ" operator, but after that i didn't know what to do, i tried once by making the bigger number the winner, and checked if they were a 0 (paper) and 2 (rock) to make rock weaker than paper on the same "if" function, but the terminal just crashed.
i don't know how to do it somwhere else and then check after, i started using batch yesterday, so i dont know praticaly anything.
also if i did any error while typing correct me becouse english is not my first language
#echo off
color f
cls
echo welcome to rock paper siscors
:LOOP
echo 0=(paper) 1=(siscors) 2=(rock)
set /p input= select one of the 3:
set /a cpu=%random% %%3
if %input% GTR 2 (echo don't type values bìigger than 2!!!!!!!!!!!!!!)
if %cpu% equ 0 if %input% equ 1 (echo you win!)
if %cpu% equ 0 if %input% equ 2 (echo you lose!)
if %cpu% equ 1 if %input% equ 0 (echo you lose!)
if %cpu% equ 1 if %input% equ 2 (echo you win!)
if %cpu% equ 2 if %input% equ 0 (echo you win!)
if %cpu% equ 2 if %input% equ 1 (echo you lose!)
if %cpu% equ %input% (echo parity!)
if %cpu% equ 0 (echo the cpu selected paper)
if %cpu% equ 1 (echo the cpu selected siscors)
if %cpu% equ 2 (echo the cpu selected rock)
goto :LOOP
Mmm.. These are my thoughs...
Scissors 1 win to Paper 0. Rock 2 win to Scissors 1; but Rock 2 should lose vs Paper. This means that Paper=0 should become Paper=3 IF the opponent is Rock 2. That is:
cpu += (!cpu) * !(input-2) * 3
We will do an extensive use of ! (Boolean NOT) operator, that returns a 1 if its operand is zero, and returns a zero in any other case. In this way, !cpu is 1 if cpu is Paper and is zero in any other case (scissors or rock).
In the same way (input-2) is zero only when input is rock, so !(input-2) returns one only when input is rock (and zero in any other case).
This means that (!cpu) * !(input-2) gives 1 when cpu is Paper AND input is Rock (and 0 in any other case). If you multiply this value times 3 (!cpu) * !(input-2) * 3 and add such a value to cpu: cpu += (!cpu) * !(input-2) * 3 then this expression will convert cpu from Paper=0 to Paper=3 when input is Rock. Ta-Da! :)
We must apply the same treatment to input when it is Paper and cpu is Rock, that is:
set /A cpu += (!cpu) * !(input-2) * 3
set /A input += (!input) * !(cpu-2) * 3
There is no way that both above expressions be executed on the same data, so it is not necessary to insert any IF to prevent to execute one or the other expression.
Also, it is simpler to get the user input via choice command that directly gives a 1..3 result, so we subtract 1 from its returned ERRORLEVEL in order to manage our standard values: 0=Paper, 1=Scissors and 2=Rock:
set /A "cpu=%random% %% 3"
choice /C PSR /N /M "Select [P]aper, [S]cissors or [R]ock: "
set /A "input=%errorlevel% - 1"
set /A "cpu += (!cpu) * !(input-2) * 3"
set /A "input += (!input) * !(cpu-2) * 3"
if %cpu% gtr %input% (echo you lose) else ...
But the SET /A command can execute several operations separated by comma, so above 4 expressions could be given in a single SET /A command. Also, we can get the name of each item via an array of names that can directly give the desired element in a single operation. Here it is the whole thing:
#echo off
setlocal EnableDelayedExpansion
rem Define the "items" array
set "item[0]=Paper" & set "item[1]=Scissors" & set "item[2]=Rock" & set "item[3]=Paper"
:LOOP
choice /C PSR /N /M "Select [P]aper, [S]cissors or [R]ock: "
set /A "input=%errorlevel%-1, cpu=%random% %% 3, cpu+=(^!cpu)*^!(input-2)*3, input+=(^!input)*^!(cpu-2)*3"
if %cpu% gtr %input% (
echo you lose
) else if %cpu% equ %input% (
echo parity
) else (
echo you win
)
echo cpu selected !item[%cpu%]!
choice /M "Play again? "
echo/
if not errorlevel 2 goto LOOP
We could also eliminate the IF's commands used to identify the winner via the following trick. If we analyse the possible values of the expression input - cpu, we'll realize that if the result is 2 or 1, you win; if it is 0, is draw; and if it is -1 or -2, you lose. We could directly use these values to define a "result" array with 5 elements this way:
rem Define the "results" array
set "result[2]=you win"
set "result[1]=you win"
set "result[0]=parity"
set "result[-1]=you lose"
set "result[-2]=you lose"
. . .
set /A "res=input-cpu"
echo !result[%res%]!
However, we could diminish the "result" array to just 3 elements if we use the "Sign" function that returns 1, 0 or -1 for positive, zero or negative values, respectively:
set /A "res=input-cpu, res=(res>>31|1)*!!res"
Here it is the final version:
#echo off
setlocal EnableDelayedExpansion
rem Define the "items" array
set "item[0]=Paper" & set "item[1]=Scissors" & set "item[2]=Rock" & set "item[3]=Paper"
rem Define the "results" array
set "result[1]=you win" & set "result[0]=parity" & set "result[-1]=you lose"
:LOOP
choice /C PSR /N /M "Select [P]aper, [S]cissors or [R]ock: "
set /A "input=%errorlevel%-1, cpu=%random% %% 3, cpu+=(^!cpu)*^!(input-2)*3, input+=(^!input)*^!(cpu-2)*3, res=input-cpu, res=(res>>31|1)*^!^!res""
echo !result[%res%]!
echo cpu selected !item[%cpu%]!
choice /M "Play again? "
echo/
if not errorlevel 2 goto LOOP
#ECHO OFF
:again
SET /a cpu=(%RANDOM% %% 3) + 1
SET "result="
SET "player="
choice /c rpsq /m "[R]ock [P]aper [S]cissors [Q]uit "
(
FOR %%e IN (1:Rock 2:Paper 3:Scissors 21 32 13) DO FOR /f "tokens=1,2delims=:" %%b IN ("%%e") DO (
IF %errorlevel%==%%b SET "player=%%c"
IF %cpu%==%%b SET "cpu=%%c"
IF %errorlevel%%cpu%==%%b SET "result=beats"
)
IF %cpu%==%ERRORLEVEL% SET "result=Draws with"
IF NOT DEFINED result SET "result=Loses to"
)
IF DEFINED player ECHO %player% %result% %cpu%&GOTO again
ECHO Quit?
ECHO Scaredy cat!
GOTO :EOF
Here's my version.
First set cpu to a random number 1 to 3
Then use choice to set errorlevel to 1(Rock) 2(Paper) 3(Scissors) or 4(Quit)
Then notice that the next statement (for...%%e...) is parenthesised, so is parsed as a single block
%%e is set to the value of each of the strings in its parentheses in turn
%%b and %%c are set to the string before and after the : delimiter in the string %%e
If %%b = errorlevel as set by the choice, set player to R/P/S
Ditto cpu from the value set by the set /a
set result to beats if {player choice number}{cpu choice number} is mentioned on the for %%e list
If both player and cpu choices are identical, set result to draws with
if result is still not assigned, it's neither a win nor a draw, so it's a loss
If player wasn't set in the loop, then errorlevel set by the choice must be 4 for Quit, otherwise output the three strings and go back to the beginning.
Whilst not a direct fix for your reported problem, here's an rewritten example batch-file to study, and which may better suit your purpose:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Color 0F
Echo Welcome to Rock Paper Scissors
:LOOP
Set /A "Opponent=(%RANDOM% %% 3) + 2, Opponent *= Opponent"
%SystemRoot%\System32\choice.exe /C RPS /N /M "[R]ock, [P]aper, or [S]cissors?"
Set /A "Result=Opponent - %ErrorLevel%"
Set "Opponent=Paper"
If %Result% Lss 4 Set "Opponent=Rock"
If %Result% Gtr 8 Set "Opponent=Scissors"
For %%G In (15 6 2) Do If %Result% Equ %%G Set /P "=You WIN: " 0<NUL
For %%G In (14 8 1) Do If %Result% Equ %%G Set /P "=You LOSE: " 0<NUL
For %%G In (13 7 3) Do If %Result% Equ %%G Set /P "=DRAW: " 0<NUL
Echo Opponent chose %Opponent%
%SystemRoot%\System32\choice.exe /M "Would you like to play again"
If Not ErrorLevel 2 Echo(& GoTo LOOP

Why is this Choice command not working (batch-file)

I have this
#echo off
:1
cls
echo Navigation: W-Up, S-Down, E-Enter
echo _________________________________
echo -(Option 1)
echo Option 2
echo Option 3
choice /c WSE /n
if ERRORLEVEL 1 goto 3
if ERRORLEVEL 2 goto 2
if ERRORLEVEL 3 goto opt1
:2
cls
echo Navigation: W-Up, S-Down, E-Enter
echo _________________________________
echo Option 1
echo -(Option 2)
echo Option 3
choice /c WSE /n
if ERRORLEVEL 1 goto 1
if ERRORLEVEL 2 goto 2
if ERRORLEVEL 3 goto opt2
:3
cls
echo Navigation: W-Up, S-Down, E-Enter
echo _________________________________
echo Option 1
echo Option 2
echo -(Option 3)
choice /c WSE /n
if ERRORLEVEL 1 goto 2
if ERRORLEVEL 2 goto 1
if ERRORLEVEL 3 goto opt3
:opt1
cls
echo You chose Option 1
pause >nul
exit
:opt2
cls
echo You chose Option 2
pause >nul
exit
:opt3
cls
echo You chose Option 3
pause >nul
exit
What it is supposed to do is look like a selection menu, but for some reason it just constantly loops through ":1" from lines 2 to 9 it just loops over and over again, why is it doing this? How do I make it not do this?
Read choice /?.
According to that help page, errorlevel(s) are supposed to be checked in reversed order.
choice /c WSE /n
if ERRORLEVEL 3 goto opt3
if ERRORLEVEL 2 goto 2
if ERRORLEVEL 1 goto 1
Why? Because if ERRORLEVEL 1 means if %errorlevel% geq 1. Alternatively, you can do:
if %errorlevel% equ 1 goto 1
if %errorlevel% equ 2 goto 2
if %errorlevel% equ 3 goto opt3
Or even crazier(but safer) with findstr.
set errlvl=%errorlevel:~-1%
echo "%errlvl%"| findstr /l /x /i """1""" && goto :1
echo "%errlvl%"| findstr /l /x /i """2""" && goto :2
echo "%errlvl%"| findstr /l /x /i """3""" && goto :opt3
We do not really need that set statement, but a precaution
Just another reminder, if the user pressed key(s) out of the "WSE", an annoyingly loud beep will occur. You may want to check out my poorly title question to find out methods of silencing them.

Using the goto command as a fallback in a batch file

How can I make it so that when the folder can't be found, the code will use the goto command?
Here's my code:
:T
Echo Folder is Already Unlocked
:CODE
if attrib -h -s "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309B}" goto T
ren "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309B}" Codes
call :c 09 " Codes Unlocked successfully
goto UNLOCK
Here's some examples - given as "answers" since the formatting is easier to use
#ECHO OFF
SETLOCAL
:: This one forces errorlevel 0
echo x|find "x" >nul
if errorlevel 1 (echo errorlevel is 1 or greater) else (echo errorlevel is 0)
:: This one forces errorlevel 1
echo y|find "x" >nul
if errorlevel 1 (echo errorlevel is 1 or greater) else (echo errorlevel is 0)
:: Now some multi-line responses
:: This one forces errorlevel 0
echo x|find "x" >nul
if errorlevel 1 (
echo errorlevel is 1 or greater
echo I say again - errorlevel 1 1 or greater
echo I say a third time - errorlevel 1 1 or greater
) else (
echo errorlevel is 0
echo again errorlevel is 0
echo once again errorlevel is 0
)
:: This one forces errorlevel 1
echo y|find "x" >nul
if errorlevel 1 (
echo Y-errorlevel is 1 or greater
echo I say again - errorlevel 1 1 or greater for Y
echo I say a third time - errorlevel 1 1 or greater - Y
) else (
echo Y-errorlevel is 0
echo Y-again errorlevel is 0
echo Y-once again errorlevel is 0
)
:: conditional modification of variable
set /a var=22
echo x|find "x" >nul
if errorlevel 1 (set /a var=%var%+10) else (set /a var=%var%-10)
echo after testing x, var is %var%
set /a var=22
echo y|find "x" >nul
if errorlevel 1 (set /a var=%var%+10) else (set /a var=%var%-10)
echo after testing y, var is %var%
:: You'll need to change these lines to files/directories that exist or don't exist
set "fileexists=c:\pdoxusrs.net"
set "direxists=c:\users"
set "filemissing=c:\missing.net"
set "dirmissing=c:\nothere"
for %%a in ("%fileexists%" "%direxists%" "%filemissing%" "%dirmissing%") do (
if exist "%%~a" (echo "%%~a" exists) else (echo "%%a" missing)
)
goto :eof
Now if errorlevel isn't being set to 0/non-zero as you appear to be expecting, then try using if exist instead. Probably easier that way, actually. Unfortunately "doesn't work" simply means nothing - we'd need to know exactly what happened, and we'd need you to edit your original posting to add-in your current code (or at least, a representative portion.)

How to store ERRORLEVEL in a variable?

I'm trying to store the ERRORLEVEL environment variable into a a local batch variable. But it always turns out to be 0.
CALL foo.exe
SET LEVEL=%ERRORLEVEL%
IF ERRORLEVEL 1 (
SET /A ERRORCOUNT=ERRORCOUNT+1
) ELSE (
SET /A OK=OK+1
)
ECHO/ >> logtemp.txt
ECHO ** EXIT %LEVEL% *******************************
I have tried to ECHO %ERRORLEVEL% but it always print 0 too.
foo.exe is generating an error and it can be seen by ECHO %ERRORLEVEL% from the command prompt and the ERRORCOUNT is updated correctly.
I suppose your problem is not the errorlevel, it's your foo.exe.
A simple test with an errorlevel works.
(call) sets the errorlevel to 1
(call)
SET LEVEL=%ERRORLEVEL%
IF ERRORLEVEL 1 (
SET /A ERRORCOUNT=ERRORCOUNT+1
) ELSE (
SET /A OK=OK+1
)
ECHO/ >> logtemp.txt
ECHO ** EXIT %LEVEL% *******************************
Second sample:
if 1==1 (
call set level=%%errorlevel%%
call echo %%level%%
call echo %%errorlevel%%
echo %errorlevel%
)
Or with delayed expansion
setlocal EnableDelayedExpansion
if 1==1 (
set level=!errorlevel!
echo !level! !errorlevel!
)
ERRORLEVEL and %ERRORLEVEL% are not the same (see http://blogs.msdn.com/b/oldnewthing/archive/2008/09/26/8965755.aspx).
The line
IF ERRORLEVEL 1
should be
IF %ERRORLEVEL% EQU 1
to yield the desire answer.

how to use goto in batch script

I have written following code
setlocal
set /A sample =1
:first
type C:\test.txt | find "inserted"
if %ERRORLEVEL% EQU 0 goto test
if %ERRORLEVEL% EQU 1 goto exam
:test
echo "testloop" >> C:\testloop.txt
set /A sample = %sample% + 1
if %sample% LEQ 4 goto first
:exam
echo "exam loop" >> C:\examloop.txt
endlocal
but it is going to lable "exam" even though error level is not equal to "1" plz help me
Your problem isn't goto, its that errorlevel requires special treatment, it's not like an ordinary environment variable. The only test you can do with errorlevel is to test whether it is greater than or equal to value.
so you have to test errorlevel values from highest to lowest because if errorlevel 1
then if errorlevel 1 will be true, but if errorlevel 0 will also be true
setlocal
set /A sample =1
:first
type C:\test.txt | find "inserted"
if errorlevel 1 goto exam
if errorlevel 0 goto test
:test
echo "testloop" >> C:\testloop.txt
set /A sample = %sample% + 1
if %sample% LEQ 4 goto first
:exam
echo "exam loop" >> C:\examloop.txt
endlocal
if you have command extensions enabled, and there is no environment variable called ERRORLEVEL (case insensitive). Then in theory you can use %ERRORLEVEL% like an ordinary environment variable. So this should also work
setlocal EnableExtensions
set /A sample =1
:first
type C:\test.txt | find "inserted"
if %errorlevel% EQU 1 goto exam
if %errorlevel% EQU 0 goto test
:test
echo "testloop" >> C:\testloop.txt
set /A sample = %sample% + 1
if %sample% LEQ 4 goto first
:exam
echo "exam loop" >> C:\examloop.txt
You need to list the error levels in descending order (errorlevel2, errorlevel1, errorlevel0...).
See this explanation and example.
You may want to consider using ERRORLEVEL as direct branching as follows:
setlocal
set /A sample =1
:first
type C:\test.txt | find "inserted"
**goto :Branch%ERRORLEVEL%**
:Branch0
echo "testloop" >> C:\testloop.txt
set /A sample = %sample% + 1
if %sample% LEQ 4 goto first
:Branch1
echo "exam loop" >> C:\examloop.txt
endlocal
May be use || instead of errorlevel for branching.
setlocal
set /a sample=1
:first
(Type c:\test.txt | find "inserted" >> c:\testloop.txt) || goto :branch1
set /a sample+=1
If %sample% leq 4 goto :first
:brabch1
Echo "exam loop" >> c:\examloop.txt
More simple way to use for loop.
For /l %%a in (1,1,4) do (
(Type c:\test.txt | find “inserted” >> c:\testloop.txt) || goto :done
)
:done
Echo “exam loop” >> c:\examloop.txt
Goto :eof

Resources