"Programming" a Batch file, IF statements inside IF statements? - if-statement

Why won't this code work correctly?
I am sorry I couldn't understand how to post the code, so here is an image of the code:
![enter image description here][1] (also, please click the link because I am a new user and I can't post images yet)
Is Command Prompt even capable of executing this "branched IF commands" correctly?
If so, what am I doing wrong? Anyone knows? Please, reply!
:STARTEXITING
"D:\dbStatusChecker\dbFi1estatus.exe" "D:\Dropbox" > dbstatus_uTorrent_Exit_Pass_1.txt
findstr /m "up to date" dbstatus_uTorrent_Exit_Pass_1.txt
if %error1eve1%==0 (
SLEEP 2
"D:\dbStatusChecker\dbFi1estatus.exe" "D:\Dropbox" > dbstatus_uTorrent_Exit_Pass_2.txt
findstr /m "up to date" dbstatus_uTorrent_Exit_Pass_2.txt
if %error1eve1%==0 (
SLEEP 3
"D:\dbStatusChecker\dbFi1estatus.exe" "D:\Dropbox" > dbstatus_uTorrent_Exit_Pass_3.txt
findstr /m "up to date" dbstatus_uTorrent_Exit_Pass_3.txt
if %error1eve1%==0 (
process -q uTorrent.exe 15
:STARTSTARTING
"D:\dbStatusChecker\dbFi1estatus.exe" "D:\Dropbox" > dbstatus_uTorrent_Start_Pass_1.txt
findstr /m "up to date" dbstatus_uTorrent_Start_Pass_1.txt
if %error1eve1%==0 (
SLEEP 2
"D:\dbStatusChecker\dbFi1estatus.exe" "D:\Dropbox" > dbstatus_uTorrent_Start_Pass_2.txt
findstr /m "up to date" dbstatus_uTorrent_Start_Pass_2.txt
if %error1eve1%==0 (
SLEEP 3
"D:\dbStatusChecker\dbFi1estatus.exe" "D:\Dropbox" > dbstatus_uTorrent_Start_Pass_3.txt
findstr /m "up to date" dbstatus_uTorrent_Start_Pass_3.txt
if %error1eve1%==0 (
D:
cd\
cd Dropbox
cd uTorrent
start uTorrent.exe
) else (
SLEEP 1
GOTO STARTSTARTING
) else (
SLEEP 1
GOTO STARTSTARTING
) else (
SLEEP 1
GOTO STARTSTARTING
) else (
SLEEP 1
GOTO STARTEXITING
) else (
SLEEP 1
GOTO STARTEXITING
) else (
SLEEP 1
GOTO STARTEXITING
For great justice: This text was OCR-ed from http://i.stack.imgur.com/RgsId.png

cmd can handle nested ifs just fine. Your problem is a different one. As it stands all your if checks, except for the first will not do what you want.
Use delayed expansion by putting a
setlocal enabledelayedexpansion
at the top of your batch file and use !errorlevel! instead of %errorlevel%.
However, since you only check for Errorlevel being 0 you can just as well do
if not errorlevel 1 ...
instead of
if %errorlevel%==0

Joey has diagnosed one problem concerning delayed expansion. You have another - you should not put a label within an IF ELSE block - you most likely will not get your desired result. See https://stackoverflow.com/a/8481978/1012053.
Christian has a great suggestion to restructure your code to get rid of the nesting.
Since you are simply executing the same commands with increasing sleep intervals, you can use a FOR /L loop to further simplify your code.
#echo off
:startExiting
set started=
for /l %%N in (1 1 3) do (
if defined started sleep %%N
set started=1
"D:\dbStatusChecker\dbFileStatus.exe" "D:\Dropbox" > dbstatus_uTorrent_Exit_Pass_%%N.txt
findstr /m "up to date" dbstatus_uTorrent_Exit_Pass_%%N.txt || goto :startExiting
)
process -q uTorrent.exe 15
:startStarting
set started=
for /l %%N in (1 1 3) do (
if defined started sleep %%N
set started=1
"D:\dbStatusChecker\dbFileStatus.exe" "D:\Dropbox" > dbstatus_uTorrent_Start_Pass_%%N.txt
findstr /m "up to date" dbstatus_uTorrent_Start_Pass_%%N.txt || goto :startStarting
)
d:
cd \Dropbox\uTorrent
start uTorrent.exe

Since all the else clauses end with a goto, why not reverse them all, then you will eliminate the nesting.
If the code works, job done. If it still doesn't work, well that's one less factor to think about.

Related

All letters, numbers and symbols in one?

Hey does anyone know if there is a command or something that allows me to have all the letters, numbers and characters in one?
:start
set input=
set /p input=[Y / N]?
if %input%==Y goto y
if %input%==N goto n
if %input%==* goto this
:y
goto end
:n
exit
:this
#echo. Only J or N
:end
Here you can already see that I tried to get everything in one with "*" which unfortunately didn't work...
Thank you for trying to help me but I would like to point out again that I need help to find something that allows me to use all the characters, letters and symbols in one.
example:
if I take y then he goes on.
if I take n then it closes. and when i use g or h he says: "can't do,
just y and n (for yes and no)"
but things like "*" or "%word%" don't work and yes, I have "choice /?" Already tried but when I do it like this it doesn't work either:
for %%i in (
D o " you " k n o w " to " h e l p " me
) do (<nul set /p "=.%bs%%%~i" & >nul ping -n 1 localhost)
# echo ?
CHOICE
[I don't care about syntax errors or something. if it works then it fits, it's just this one thing to use all characters, letters and symbols in one.]
No hate <3
if has no wildcard, but as I already commented, you don't need the third if at all. If Y and N are already handled, it can only be "anything else"
:start
set "input="
set /p "input=[Y / N]? "
if "%input%"=="Y" goto y
if "%input%"=="N" goto n
echo it's Y or N, nothing else&goto :start
The quotes makes it a little bit safer, but note this still isn't safe at all.
Cmd handles several characters (so called "poison chars" like <>|&"!) different (and even more under certain conditions).
A more secure method:
#echo off
setlocal enabledelayedexpansion
:loop
set "input="
set /p "input="
>nul 2>&1 (
echo/!input!|findstr /x "Y" >nul && goto YES
echo/!input!|findstr /x "N" >nul && goto NO
)
echo FAIL
goto :loop
:YES
echo yeah
goto :eof
:NO
echo nope
goto :eof
(Disclaimer: I'm quite sure, someone will find an input-string to make it fail too)
Note: both if and findstr support the /i switch to make them case-insensitive.
And just for the sake of showing everyone else how to perform this task using the appropriate commands:
%SystemRoot%\System32\choice.exe
If ErrorLevel 2 Exit /B
Rem The code you had under :end replaces this line

Alternative to grep for isolating specific text in Windows command line

My network changes rather dynamically and unfortunately I am forced to run Windows.
This script works because I have installed GNU tools for Windows and can use grep.
I would like to be able to run this script on any windows machine without having to install anything (grep etc). I used findstr in this at first but could not get it to show only what matches the regex string.
#echo off
set %IPLIST% = nul
Echo.
Echo "Pinging all local Gateways"
ipconfig | findstr /i "Gateway" | grep -o "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" > %IPLIST%
For /F "Usebackq Delims=" %%# in ("%IPLIST%")
do (
Echo+
Echo [+] Pinging: %%#
Ping -n 1 "%%#" 1>nul && (
Echo [OK]) || (
Echo [FAILED])
)
Echo.
Echo.
Echo "now testing your internet connection"
Echo .
Echo ...
if %errorlevel% == 0 (
echo ....you're all good bro.
) else (
ping -n 3 "8.8.8.8" | findstr /r /c:"[0-9] *ms"
if %errorlevel% == 1 (
echo ....all is lost
)
)
Echo.
You have a number of problems with the script.
set %IPLIST% = nul
This would yield a syntax error because iplist is likely undefined, and you are attempting to set the variable contents of iplist to "nul"
The resolution of this would be
set = nul
Further, spaces on either side of the = are included in the variable/value set, so removing the %s would set the value of iplistSpace to Spacenul
Had iplist indeed been set up to nul then your ipconfig command would have simply dumped its eventual output into the bit-bucket as it would have been sent to nul.
For /F "Usebackq Delims=" %%# in ("%IPLIST%")
The do ( must be on the same physical line as the "for"
<opinion>Using non-alphas as metavariables is not a good idea as it is not officially supported <\opinion>
if %errorlevel% == 0 (
echo ....you're all good bro.
) else (
ping -n 3 "8.8.8.8" | findstr /r /c:"[0-9] *ms"
if %errorlevel% == 1 (
echo ....all is lost
)
)
Because of the delayed expansion trap (all %var% in a block (parenthesised sequence of statements) are replaced by their value at parse-time) the innermost %errorlevel% here would be replaced by whatever errorlevel was set to when the outermost if was encountered. To interpret the ping output, you'd need to either invoke delayedexpansion (many, many SO items on this subject) or use the old original if errorlevel n... construct, where the if condition is true if the current errorlevel is n or greater than n.
So - reconstructing using batch features,
#ECHO OFF
SETLOCAL
Echo.
Echo "Pinging all local Gateways"
For /F "tokens=2 Delims=:" %%a in ('ipconfig ^| findstr /i "Gateway"') DO IF "%%a" neq " " (
Echo+
Echo [+] Pinging: %%a
Ping -n 1 %%a 1>nul && (
Echo [OK]) || (
Echo [FAILED])
)
Echo.
Echo.
Echo "now testing your internet connection"
Echo .
Echo ...
if %errorlevel% == 0 (
echo ....you're all good bro.
) else (
ping -n 3 "8.8.8.8" | findstr /r /c:"[0-9] *ms"
if ERRORLEVEL 1 IF NOT ERRORLEVEL 2 (
echo ....all is lost
)
)
Echo.
GOTO :EOF
The 'for /ftokenises the output of the command in single-quotes using:as a delimiter and picking the second token to apply to%%a`.
The | needs to be escaped by a caret to tell cmd that it is part of the command to be executed, not part of the for.
The for processes the output of ipconfig... so %%a has the form Spacexxx.xxx.xxx.xxx
On my machine, xxx... was missing on one line, so I filtered out the single-space response.
Pinging %%a without the quotes adds an extra space into the ping line, which is harmless. With the quotes, it didn't like it.
Then the appendix...
I'm not sure what you're really attempting here. Perhaps it was a frustrated debug attempt.
errorlevel will be set to whatever the last ping result was. This is logically unpredictable.
I've shown a correct method of interpreting the findstr errorlevel result. I'm not sure that your regex is correct here...but the all is lost message would only be shown if findstr sets errorlevel to 1.

Batch Random Number Generator - Generates Same Number as Before

Basically, what is happening is my code continues to generate the same number. I have turned echo off to see the problem and the actual %random% variable is changing, but it seems like it does the math and says "No, it's really this number." Here's the code:
set /a num=(24 * %random%) / 32768 + 1
I have tested that code by itself and it works fine. However when I add my if statements* to the code, it goes all whack. So, the question is, how do I fix this and why is it happening?
*My if statements:
if "%num%"=="24" (
echo X
set /p ans=
if "%ans%"=="litin" (
echo.
echo Correct!
pause>nul
goto generate
)
)
All of my if statements look like that.
Sounds like you might have an issue with variable expansion. Assuming you are doing this stuff in a loop.
Try adding setlocal at the top of your program like this:
setlocal ENABLEDELAYEDEXPANSION
And endlocal at the end of your program:
endlocal
Now, when you need to use a variable that is changing inside a loop, use the ! syntax instead of %:
if "!num!"=="24" (
echo X
set /p ans=
if "!ans!"=="litin" (
echo.
echo Correct!
pause>nul
goto generate
)
)
You might want to use EQU for comparing numbers. So try this
if "%num%" EQU 24 (
...
)

batch file: if %variable% (commands)

i want to use my %variable% to manage the conditional clauses in a IF.. THEN.. ELSE in a batch file.
Something like the following:
set variable=%%homedrive%% EQU C:
if %variable% (
echo test ok
) else (
echo test fail
)
if i write on a cmd console:
set test=1 equ 1
if %test% echo OK
it works!
i'll use it in a for /f cicle:
this is my pseudo codethis is my pseudo code to correct
(
rem echo "%systemdrive%;;"
echo "%%COMPUTERNAME%% EQU [x];[some parameters1]"
echo "%%USERNAME%% NEQ [y];[some parameters2]"
echo "%%LOGONSERVER%% EQU [z];[some parameters3]"
[..]
) > "%temp%\CSG_fs.tmp"
[..]
for /f "usebackq tokens=1-2* delims=;" %%a in ("%temp%\CSG_fs.tmp") do (
set cond=%%a& set cond=!cond:~1!
set parm=%%b& set parm=!parm:~0,-1!
echo - cicle: "!cond!" --^> "!parm!"
call if !cond! call:CSG_sub_fs !parm!
echo - done
)
goto:eof
:CSG_sub_fs
[..]
goto:eof
--edit--
how can i use the variable !cond! to decide if execute the call to CSG_sub_fs?
call if !cond! call:CSG_sub_fs !parm!
does not work because it returns: "Can not find the batch label specified - IF"
and if i use
if !cond! call:CSG_sub_fs !parm!
it will say: "call:CSG_sub_fs not expected"
Well - there doesn't seem to be a question, so it's not that easy to answer.
You have a problem with
echo "^%COMPUTERNAME^% EQU [x];[some parameters1]"
because ^ does not escape % - % escapes % - use %%COMPUTERNAME%%...
(you should have been able to check this just by TYPEing "%temp%\CSG_fs.tmp"
Next problem is that
for /f "tokens=1-2* delims=; usebackq" %%a in (%temp%\CSG_fs.tmp) do (
may process the file %temp%\CSG_fs.tmp provided %temp%\CSG_fs.tmp contains no spaces, semicolons or commas. If it contains any of these deafult separators, or certain other characters with a special meaning, then you must enclose the filename in double-quotes "%temp%\CSG_fs.tmp"and use the usebackq option.
You've attempted to use usebackq but DELIMS must be the LAST option if it is used. Your code would set ";","","u","s","e","b","a","c","k" and "q" as delimiters.
Beyond that, perhaps if you explain what you intend to achieve, we'd be able to devise the appropriate code.
Try this:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
CLS
REM I'm setting these variables for testing.
REM That isn't ususally a good idea but the SETLOCAL
REM will ensure they are restored on exit
SET computername=[x]
SET logonserver=[z]
(
rem echo "%systemdrive%;;"
echo "%%COMPUTERNAME%% EQU [x];[some parameters1]"
echo "%%USERNAME%% NEQ [y];[some parameters2]"
echo "%%LOGONSERVER%% EQU [z];[some parameters3]"
) > "%temp%\CSG_fs.tmp"
for /f "usebackqtokens=1-2* delims=;" %%a in ("%temp%\CSG_fs.tmp") do (
set cond=%%a& set "cond=IF !cond:~1! CALL :csg_sub_fs "
set parm=%%b& set parm=!parm:~0,-1!
CALL :varcmd "!cond!" "!parm!"
)
GOTO :eof
:varcmd
%~1 %~2
GOTO :eof
:csg_sub_fs
ECHO parameters supplied to csg_sub_fs were: %*
GOTO :eof
I've forced the variablenames to match the conditions you've used in order to trigger the subroutine calls. Change as you need to prove your concept.
And dont worry about imperfect English. I'm sure I wouldn't do as well in your language!

Regex to identify DOS environment variables within braces

The following DOS script snippet has a bug:
if not exist %MyFolder% (
mkdir %MyFolder%
if %errorlevel% GEQ 1 (
rem WARNING: the line above has a bug!
rem %errorlevel% will be the errorlevel
rem of the if statement because of the (parentheses)
echo Error: Could not create folder %MyFolder%
goto AnErrorOccurred
)
)
The fix is to use setlocal enabledelayedexpansion as follows:
setlocal enabledelayedexpansion
if not exist %MyFolder% (
mkdir %MyFolder%
if !errorlevel! GEQ 1 (
rem WARNING: the line above has a bug!
rem !errorlevel! will be the errorlevel
rem of the if statement because of the (parentheses)
echo Error: Could not create folder %MyFolder%
endlocal & goto AnErrorOccurred
)
)
endlocal
A full explanation of why is available here: Batch file fails to set environment variable within conditional statement
I want to audit my code to find instances of this bug, I figure a Regex would be an appropriate match, but haven't managed to get one working...
I think the ingredients should be:
Match an environment variable surrounded with %percentsigns%
That is inside (parentheses)
Any suggestions?
grepWin
I would use grepWin. Depending on the number of instances you have to find, you could write a regex that will give you all of them, plus some false positives.
Example: bug.bat
if not exist %MyVar% echo Hi!
if not exist %MyFolder% (
mkdir %MyFolder%
if %errorlevel% GEQ 1 (
rem WARNING: the line above has a bug!
rem %errorlevel% will be the errorlevel
rem of the if statement because of the brackets
echo Error: Could not create folder %MyFolder%
goto AnErrorOccurred
)
)
Then use a regular expression to match all lines that start with if and have an open parenthesis:
$ grep "^[ \t]*if.*(" bug.bat
if not exist %MyFolder% (
if %errorlevel% GEQ 1 (
grepWin will show you all the files that match.
Percent Symbols
By request:
grep "^[ \t]*if.*%.*%.*(" bug.bat
You can't solve it with Regex, because you can't count the parenthesis with a regular language. For example:
Stuff (
More Stuff (
Less Stuff )
A %var%
Less Stuff )
There is no ( between the last ) and the variable. Since I can't count how many `( appear before to know if there's one open, I can't do this with regular expressions.
As you can see, he is using ! rather than % even in the rootlevel of the batch.
So basically you should be able to alternate every % to an ! for your environmental variables.
One other way is to use the AND (&&) and OR (||) tests for success (errorlevel 0) or error (errorlevel > 0), as in:
if not exist %MyFolder% mkdir %MyFolder%|| (
echo Error: Could not create folder %MyFolder%
goto AnErrorOccurred
)
I hope this can help.
And by the way, you do not fail to set the variable, you fail to read it back.
What happen is, within parenthesis, using %%'s give you the states which was before you entered the said parenthesis. The only thing I knows work well is the math "set /a toto+=1" which will correctly increment the variable. Otherwise you have two options:
Either use a called function to set the variable or use the setlocal ENABLEDELAYEDEXPANSION statement, as previously stated, and use !!'s within the parenthesis.