I'm doing a project to help myself learn batch a little better. I have code which is meant to be a "UI" of sorts.
The snippet I have an issue with is this:
:install_check
if exist UI (
echo UI is already installed; reinstall?
CHOICE
if Errorlevel 1 goto :del
if Errorlevel 2 goto :return
cls && goto :install_check
)
goto :install_yes
I know the naming conventions and some of the coding stuff isn't perfect, but I really see no reason why every time it runs it goes to :del no matter what I type in for choice.
I've changed the choice switches and moved it around to be all in one line but it still doesn't want to work. The if that it is nested in is meant to check if a file is present on the computer, so it is a requirement but also may be the issue?
I tried looking around on this site but nothing will help my issue, any help is gladly accepted!!
Check the errorlevels in reverse-order.
if errorlevel n
means if errorlevel is n or greater
hence, errorlevel 2 will be interpreted as true for if errorlevel 1
As a solution has already been determined, the following example, (using your existing label names), restructures your code a little:
:install_check
ClS
If Not Exist "UI" GoTo install_yes
Choice /M "UI is already installed; reinstall"
If Errorlevel 2 GoTo return
GoTo del
If the next line/label in your code is :del, you may also remove line six.If the name UI belonged to a directory instead of a file then you'd change the third line to If Not Exist "UI\" GoTo install_yes.
ERRORLEVEL doesn't update inside control blocks like IF statements unless you use !ERRORLEVEL! instead of %ERRORLEVEL% and use this command at the start of your code: setlocal ENABLEDELAYEDEXPANSION
see http://batcheero.blogspot.ca/2007/06/how-to-enabledelayedexpansion.html
Related
I'm trying to take some user input defined variables to decide whether or not to enter the loop and execute a copy and rename followed by deletion of the original file as it will no longer be needed.
set /p multiTune="Does your tune file need to be shared with multiple
Element sequences? (y/n) "
Echo Multi Tune is %multiTune%
if "%multiTune%"=="y" (set /p tuneCount="How many sequences will need to share your tune file? ")
Echo Tune count is %tuneCount%
pause
if "%multiTune%"=="y" (SET /p tuneName="Enter the file letter/number combination for the R quant of your tune file. ") else (#ECHO The user specified there is no need for a second tune.)
Echo Tune Name is %tuneName%
pause
if "%multiTune%"=="y" (SET /a tuneCount+=1) else(set /a tuneCount-=tuneCount)
Echo Tune count is now %tuneCount%
pause
:loop
if "%tuneCount%"=="0" goto exitloop
Set /p seqNumber="Enter the number for one of the sequences."
copy %tuneName%.D.pdf "S%seqNumber%-TUN1_%tuneName%.D.pdf"
echo %tuneName%.D.pdf renamed to S%seqNumber%-TUN1_%tuneName%.D.pdf
pause
Set /a tuneCount-=1
if "%tuneCount%"=="1" DEL "%tuneName%.D.pdf"
if "%tuneCount%"==1 goto exitloop
Echo %tuneCount%
pause
goto loop
:exitloop
All of the echos and pauses are just for testing purposes to make sure I have the correct values in my variables.
The batch file runs fine with the variables containing the correct strings and values up until the line:
if "%multiTune%"=="y" (SET /a tuneCount+=1) else(set /a tuneCount-=tuneCount)
The file says something is unexpected and closes at this point so i havent gotten a chance to figure out if the looped portion even works. The point of the +1 is so that it enters the loop and executes the commands until it gets to 1 and skips the loop if it equals 0.
I read a bunch of information about setlocal delayedexpansion and using !'s around variables instead of %'s. I'm not sure how to implement this or if this applies to my problem at all. I know there is probably an easier way to do the if statements but I'm a novice and that was the easiest way for me to understand it as I've been learning on the fly through trial and error, and everything you see is the results of a single day of learning.
Any help would be much appreciated. I tried to be as detailed as possible about what it is I'm trying to do but if you have any questions I will do my best to answer.
I really think you are making the things so MUCH complicated...
Have a corrected piece of the code you provided us (Note: I did not touch the loop subroutine to be on-topic):
#echo off
choice /m "Does your tune file need to be shared with multiple element sequences? (y/n) " /C:yn /N
rem Echo Multi Tune is %errorlevel%
rem If errorlevel equals to 1 user input is "Y", it is 2 it is "N". (I commented the "echo" command as it changes the errorlevel value).
if errorlevel 2 goto question_N
if errorlevel 1 goto question_Y
:question_Y
set /p tuneCount="How many sequences will need to share your tune file? "
set /p tuneName="Enter the file letter/number combination for the R quant of your tune file. "
SET /a "tuneCount+=1"
goto loop
:question_N
set /p tuneCount="How many sequences will need to share your tune file? "
ECHO The user specified there is no need for a second tune.
set /a "tuneCount-=tuneCount"
goto loop
:loop
rem [Code you provided above]
I hope you are fine with this, testing it and it works!
I'm trying to handle missing label errors in a batch file (Windows 10). My batch file currently uses a GOTO based on a passed parameter like this:
MYSCRIPT.bat choice1
I'm trying to do something simple with a simple syntax so that you don't have to include complex menus or lists. I hoped to do something simple in the batch file such as:
GOTO %1%
The problem occurs when the choice is misspelled, missing (not found.) I tried some of the examples for similar handling that I found on this site, but I either have the wrong situation or just don't quite understand how to apply it.
I'm sure that at least one person will scold me for not doing it in PowerShell or VBasic or something else. So I will go ahead and apologize in advance. Frankly, I don't really know how to do what I want to do in any of those. (Some will quip that I don't know how to do it in BATCH either otherwise I wouldn't be asking for help.)
I tried using a "FOR" to parse the file for an instance of the label, and also an "IF ERRORLEVEL 1" but it seems that it's not branching where it needs to go. For instance, if the label is found, go there; if not, go back to the beginning to give an opportunity to input something else.
Thanks in advance for any ideas that might be offered.
There is no way to handle this error and continue with goto command; just with call:
#echo off
setlocal EnableDelayedExpansion
call :%1 2>NUL
if errorlevel 1 echo Error: label "%1" does not exist
goto :EOF
:one
echo Section one
exit /B
:two
echo Section two
exit /B
I have asked other questions about Concatenated commands in DOS, but am obviously not yet that confident with the full bredth of things to take into account.
Can someone take a look at the below code and output on my system and see if they can advise what syntax is wrong (Note, I have broken the lines manually):
%comspec% /v:on /k "(for /f "tokens=2*" %a in ('reg query hkcu\software\microsoft
\windows\currentversion\policies\system /v DisableTaskMgr') do #set DisableTaskMg
r=%b) 2>nul & set DisableTaskMgr& pause & (if defined programfiles^(x86^) (set
"ProgramFiles(x32)=%programfiles(x86)%") else (set "ProgramFiles(x32)=%programfil
es%")) & !ProgramFiles(x32)!\Mozilla\Firefox\Firefox.exe -chrome chrome://browser
/content & echo. & if defined DisableTaskMgr (echo DisableTaskMgr reg key existed
prior to running, and... & (set DisableTaskMgr=%DisableTaskMgr:~2,3% & echo !
DisableTaskMgr! & reg add hkcu\software\microsoft\windows\currentversion\policies
\system /v DisableTaskMgr /t REG_DWORD /d %DisableTaskMgr% & if %DisableTaskMgr%
eql 0 (echo Previous state was Task Manager enabled) else (echo Previous state
was Task Manager DISabled))) else (echo DisableTaskMgr reg key DID NOT exist pri
or to running & reg delete hkcu\software\microsoft\windows\currentversion\polici
es\system /v DisableTaskMgr /f)"
.
I have tried cutting out parts of the code to fix individual parts, but my attempts at trial and error prove that I don't have much of an idea of what is wrong, and that I am not going to get this solved on my own very fast :(
Your IF comparison operator is wrong. You have eql - it should be equ.
I have no idea if that is your only problem - you have a horrific maintenance issue with that beast of a statement.
You might be better off creating a batch file with the same logic but formatted nicely. You can then simply call the batch file instead of trying to embed the entire complex process as one single complex command.
I can see your problem right here! It's your code! *grin*
Seriously though, even if you intend to maintain that mess, I recommend that split it up into it's constituent components for debugging purposes. You can even avoid the sometimes mysterious block errors by putting what is inside () blocks into separate subroutines. By turning this sort of thing...
if statement (
code block 1
code block 1
code block 1
code block 1
) else if (
code block 2
code block 2
code block 2
code block 2
)
...into this sort of thing:
if statement (
call :CodeBlock1
) else if (
call :CodeBlock2
)
goto :eof
:CodeBlock1
code
code
code
code
goto :eof
:CodeBlock2
code
code
code
code
goto :eof
Trying to debug that as a single line means keeping the whole thing, and how it interacts, constantly in mind. And basically having to guess at which similar looking bit of code actually created the error you're trying to fix.
I've personally wasted a good bit of time trying to fix perfectly good code, while not realizing that the error that I was looking at was actually further down in the code block.
After you've found and fixed your errors you can jam it all back into a single line again if you like. Overcoming a challenge does not necessarily mean doing it the hardest way possible. Overcoming a challenge the easiest way is also, by definition, overcoming a challenge.
I have been stuck on this silly if statement, whatever i do, I cannot get the if statment to go to the correct label.
Hitting 'y' works, cmd-prompt stops at START DEPLOY
BUT, if I type 'n' cmd prints START DEPLOY then goes to end, instead of going direct to the cancel label.
Can you help?
:getConfirmation
set /p confirmDeploy =Confirm deployment of code [y/n] ?:
if "%confirmDeploy%"=="y". goto deployCode
if "%confirmDeploy%"=="n". goto cancelDeploy
:deployCode
ECHO START DEPLOY
goto end
:cancelDeploy
ECHO DEPLOY CANCELLED
goto end
Try this:
#echo off
:getConfirmation
set /p confirmDeploy=Confirm deployment of code [y/n] ?:
if %confirmDeploy%==y goto :deployCode
if %confirmDeploy%==n goto :cancelDeploy
:deployCode
ECHO START DEPLOY
goto end
:cancelDeploy
ECHO DEPLOY CANCELLED
goto end
If we ignore the fact that required input was y. or n. (due to the . in the if comparison), nobody noticed the ACTUAL problem with c14kaa's script (except Nick DeVore but didn't say why). The original script had the line
set /p confirmDeploy =Confirm deployment of code [y/n] ?:
Nick mentioned that this did not put the response into the variable. That is because it was putting the response into "confirmDeploy " (the space is part of the variable name, just another foible of cmd's input parsing). Thus when c14kaa used %confirmDeploy%, it would have expanded to %confirmDeploy% (i.e. been taken literally) unless that variable had been set elsewhere. I can only assume that c14kaa had turned off echoing because the fact that confirmDeploy did not substitute (or contained something other than y or n) would have been a big clue. It would have also revealed the problem with the . in the if statement.
As for the other suggestions, having "" around the variable (and hence needed in the matching string) is preferred to stop syntax errors when the variable is blank (generating the statement 'if == y', what jeb means by "failing"), the : before the label name in the goto is ignored and there needs to be a space after the /I in John's version (even though the if command has only one option, some commands have many and they can be put together such as in "findstr /ivn ..." so the space marks the end of the list).
The only other comment I would make is that c14kaa assumes that the user will always enter the correct response (y or n) because otherwise the script will "fall through" into the :deployCode section (probably not the ideal default behaviour). This explains the response obtained to the suggestion by Matt (echo bad input). Since the response was being put into confirmDeploy<space> it meant that both tests (using confirmDeploy without the space) failed.
Taking all of the above leaves us with Reny's version (with some explanation added).
You're on the right track, just needed to clean up syntax and spacing errors. This will work:
#echo off
:getConfirmation
set /p confirmDeploy=Confirm deployment of code [y/n] ?:
if /I "%confirmDeploy%"=="y" goto deployCode
if /I "%confirmDeploy%"=="n" goto cancelDeploy
REM added goto getConfirmation in case of invalid responses
goto getConfirmation
:deployCode
ECHO START DEPLOY
goto end
:cancelDeploy
ECHO DEPLOY CANCELLED
goto end
The problem is that neither of your tests work. You're checking for the user entering something like y. or n. (but I don't think you can actually enter anything that will match).
Try with:
if "%confirmDeploy%".=="y". goto deployCode
if "%confirmDeploy%".=="n". goto cancelDeploy
echo bad input
goto getConfirmation
...
try this too:
#echo off
:getConfirmation
set /p confirmDeploy=Confirm deployment of code [y/n] ?:
if /I%confirmDeploy%==y goto :deployCode
if /I%confirmDeploy%==n goto :cancelDeploy
:deployCode
ECHO START DEPLOY
goto end
:cancelDeploy
ECHO DEPLOY CANCELLED
goto end
The /I argument makes it case-insensitive.
I'm attempting to make the errorlevel environment variable increase by one every time a certain section of my code is ran. I read in set /? that you can use /p to list an expression that needs to be calculated after the equals sign, however it doesn't seem to change the errorlevel at all.
This is what I have.
if not %cd2%==%cd1% (goto :installauto) else set /p errorlevel=(%errorlevel%+1)
Thanks for the help, and sorry if this is a noob question. >.<
EDIT: Wow, I'm an idiot. The /a tag is used for expressions. Sorry lol.
It's a bad idea to change/create an errorlevel variable, as this is not the errorlevel for other programs.
Then you can not access the "real" errorlevel anymore.
You could better do this with an other variable and exit the bacth file with exit /B
set myErr=0
if not %cd2%==%cd1% (
goto :installauto
) else (
set /a myErr=myErr+1
)
exit /b %myErr%