Strange behavior of batch file - windows

I have two cmd files.
child.cmd:
#echo off
exit 1
parent.cmd:
#echo off
cmd /C child.cmd
if %errorlevel% EQU 0 (
echo OK
) else (
echo ERROR
)
If to run parent.cmd, then ERROR will be printed.
But if a little change parent.cmd, then OK will be printed:
#echo off
if "YES" EQU "YES" (
cmd /C child.cmd
if %errorlevel% EQU 0 (
echo OK
) else (
echo ERROR
)
)
Why OK is printed in the second example?

inside a code block you need delayed expansion to access %variables%:
#echo off &setlocal enabledelayedexpansion
if !errorlevel! EQU 0 (

You can also use this syntax without delayed expansion:
if errorlevel 1 if not errorlevel 2 ( echo error )

Related

Exit with errorlevel from windows batch

In my batch file I have a function where use this command to connect to a remote host:
net use %alias%: \\%host%\%root%$ %usrPwd% /USER:%usrName% >> %logfile% 2>&1 || ( call :exitIfError ERROR)
I created this function:
:exitIfError
setlocal
(set txt=%~1)
if not ERRORLEVEL 0 ( echo %txt% && exit /B %errorlevel%)
endlocal
goto :eof
If I enter an incorrect password is generating the error, but doesn't finish with error and the value of %errolevel% is 0
instead of 2. Suggestions?
:exitIfError
if ERRORLEVEL 1 (echo %~1& exit /B %errorlevel%)
exit /b 0
There appears to be no reason to set txt

Checking error level while building with sbt

I want to write a windows .cmd script that publishing all project modules into local repository. But I want to stop at first error that may be occur. I'm checking %ERRORLEVEL% but it's always equals to 0 even if sbt publish-local command fails with some error.
#echo on
#setlocal enabledelayedexpansions
set modules=^
sbt-common^
common^
for %%A in (%modules%) do (
echo ======================================
echo = PUBLISHING %%A =
echo ======================================
cd %%A
call sbt publish-local
echo %ERRORLEVEL% :: <- Always = 0
if ERRORLEVEL 1 goto error
)
:error
#endlocal
exit /B 1
Any help will be appreciated.
Try this:
#echo on
#setlocal EnableDelayedExpansion
set modules=^
sbt-common^
common^
for %%A in (%modules%) do (
echo ======================================
echo = PUBLISHING %%A =
echo ======================================
cd %%A
call sbt publish-local
echo !ERRORLEVEL!
if !ERRORLEVEL! geq 1 goto error
)
:error
#endlocal
exit /B 1
Note that EnableDelayedExpansion should not have a following s, and you should use ! instead of % inside parenthesis in batch.

Equal variables - Batch

So, I've the following batch script:
#echo off
set /p name=
rem a random number, don't care about it.
set complete_name=%name%.Creepy
Goto STEP1
:STEP1
echo %complete_name%|findstr /C:"9000" >nul 2>&1
if not errorlevel 1 (
goto 9000
) else (
GOTO CHECK2
)
:CHECK2
echo %complete_name%|findstr /C:"930" >nul 2>&1
if not errorlevel 1 (
goto 930
) else (
GOTO CHECK3
)
:CHECK3
echo %complete_name%|findstr /C:"310" >nul 2>&1
if not errorlevel 1 (
goto 310
) else (
ECHO PROBLEM
)
:9000
ECHO 9000
PAUSE
:930
ECHO 930
PAUSE
:310
ECHO 310
PAUSE
I want it to check if "9000" is in the variable or not, same for "930" and "310". And if none of these numbers are in the variable Echo problem. But everytime i run this script it goes to ECHO PROBLEM even if 9000/920/310 is in %complete_name%. So, is this the right way to check if a variable is in another one or there is an easier way to do it?
So I've tried this code:
#echo off
set name=310
set complete_name=%name%.Creepy
Goto STEP1
:STEP1
setlocal
if "%complete_name:9000=%"=="%complete_name%" (
if "%complete_name:930=%"=="%complete_name%" (
if "%complete_name:310=%"=="%complete_name%" (
echo PROBLEM
) else (
goto 9000
)
) else (
goto 930
)
) else (
goto 310
)
goto :eof
but I'm stuck at echo problem...
Save next code snippet, possibly named blabla.bat:
#Echo OFF
setlocal
set complete_name=%1
if "%complete_name:9000=%"=="%complete_name%" (
if "%complete_name:930=%"=="%complete_name%" (
if "%complete_name:310=%"=="%complete_name%" (
echo problem
) else (
echo valid 310
)
) else (
echo valid 930
)
) else (
echo valid 9000
)
Exit /B
and watch the output from
blabla x9000y
blabla x930y
blabla x310y
blabla x9a0b0c0y
That's a way of 1. nested IF ... ( ... ) ELSE ( ... ) and 2. using "Edit/Replace" a variable
Or, if GOTOs considered necessary, there is something similar with For loop (a good thought topic as well..).
#Echo OFF
setlocal EnableDelayedExpansion
set complete_name=%1
for %%G in (9000 930 310) DO (
if /I "!complete_name:%%G=!" neq "%complete_name%" GOTO :%%G
)
echo problem %complete_name%
GOTO :commonEnd
:9000
Echo valid 9000 %complete_name%
GOTO :commonEnd
:930
Echo valid 930 %complete_name%
GOTO :commonEnd
:310
Echo valid 310 %complete_name%
GOTO :commonEnd
:commonEnd

IF, CALL, EXIT and %ERRORLEVEL% in a .bat

Can anyone please help me understand the behaviour of %ERRORLEVEL% variable and why it's not being set after a CALL while being inside an IF, i.e. the ECHO %ERRORLEVEL%.2 line?
#ECHO OFF
SET ERRORLEVEL
VERIFY > NUL
ECHO %ERRORLEVEL%.0
IF ERRORLEVEL 1 ECHO SNAFU
IF %ERRORLEVEL% == 0 (
ECHO %ERRORLEVEL%.1
CALL :FOO
ECHO %ERRORLEVEL%.2
IF ERRORLEVEL 42 ECHO 42.3
)
GOTO :EOF
:FOO
EXIT /B 42
GOTO :EOF
STDOUT
C:\Users\Ilya.Kozhevnikov\Dropbox>foo.bat
Environment variable ERRORLEVEL not defined
0.0
0.1
0.2
42.3
However, without IF the %ERRORLEVEL% variable is set as expected.
#ECHO OFF
SET ERRORLEVEL
VERIFY > NUL
ECHO %ERRORLEVEL%.0
IF ERRORLEVEL 1 ECHO SNAFU
REM IF %ERRORLEVEL% == 0 (
ECHO %ERRORLEVEL%.1
CALL :FOO
ECHO %ERRORLEVEL%.2
IF ERRORLEVEL 42 ECHO 42.3
REM )
GOTO :EOF
:FOO
EXIT /B 42
GOTO :EOF
STDOUT
C:\Users\Ilya.Kozhevnikov\Dropbox>foo.bat
Environment variable ERRORLEVEL not defined
0.0
0.1
42.2
42.3
When the cmd parser reads a line or a block of lines (the code inside the parenthesis), all variable reads are replaced with the value inside the variable before starting to execute the code. If the execution of the code in the block changes the value of the variable, this value can not be seen from inside the same block, as the read operation on the variable does not exist, it was replaced with the value in the variable
To solve it, you need to enable delayed expansion, and, where needed, change the syntax from %var% to !var!, indicating to the parser that the read operation needs to be delayed until the execution of the command.
#ECHO OFF
setlocal enabledelayedexpansion
SET ERRORLEVEL
VERIFY > NUL
ECHO %ERRORLEVEL%.0
IF ERRORLEVEL 1 ECHO SNAFU
IF %ERRORLEVEL% == 0 (
ECHO !ERRORLEVEL!.1
CALL :FOO
ECHO !ERRORLEVEL!.2
IF ERRORLEVEL 42 ECHO 42.3
)
GOTO :EOF
:FOO
EXIT /B 42
GOTO :EOF
MC ND answered the question already well.
Here is an alternative code showing both: expanded and delayed expansion of ERRORLEVEL.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
VERIFY > NUL
ECHO !ERRORLEVEL!.0 delayed
ECHO %ERRORLEVEL%.0 expanded
IF ERRORLEVEL 1 ECHO SNAFU
IF !ERRORLEVEL! == 0 (
ECHO !ERRORLEVEL!.1 delayed
ECHO %ERRORLEVEL%.1 expanded
CALL :FOO
ECHO !ERRORLEVEL!.2 delayed
ECHO %ERRORLEVEL%.2 expanded
)
ENDLOCAL
GOTO :EOF
:FOO
EXIT /B 42
GOTO :EOF
Microsoft describes the behavior of delayed expansion in help of command set which can be read in a command prompt window after entering set /? or help set

Windows Batch For Loop: having trouble with the following code

set checker=0
for %%a in (%namelist%) do (
:startLoop
findstr "completed" %%a_Logs.txt
IF ERRORLEVEL 1 (
IF %checker%==120 (
set checker=0
goto endLoop
)
set /a checker=%checker%+1
#ping 127.0.0.1 -n 1 -w 1000 > nul
findstr "ERROR" %%a_Logs.txt
IF ERRORLEVEL 1 (
echo Waiting 1 second before rechecking (Max 2 mins)
echo time elapsed %checker% seconds
echo.
goto startLoop
)
findstr "ERROR" %%a_Logs.txt
IF NOT ERRORLEVEL 1 (
echo ERROR: %%a Error found
goto endLoop
)
)
findstr "completed" %%a_Logs.txt
IF NOT ERRORLEVEL 1 (
echo %%a completed
)
:endLoop
)
The above piece of code is to do the following:
Parse the variable namelist(where the contents are separated by spaces)
Check if "completed" is present in the %%a_Logs.txt file
If it is present, then iteration over, If it is not, then check for the string "ERROR" in same file
If ERROR is present, then output ERROR MSG and end iteration
If ERROR is not found, keep rechecking for the next 120 seconds before ending iteration
I keep getting the following output
FINDSTR: Cannot open %a_Logs.txt
You are attempting to GOTO a label within a FOR loop - that simply doesn't work. The moment a FOR loop executes GOTO, the loop is terminated, and the FOR context is lost. So your %%a FOR variable is no longer defined. A similar issue happens with IF statements, as described at (Windows batch) Goto within if block behaves very strangely.
You also have a problem when you attempt to expand %checker% within the same parenthesized code block that sets the value. That expansion occurs at parse time, and the entire block is parsed at once. So the value you see will always be the value that existed before the block was entered. The solution is to enable delayed expansion and use !checker! instead of %checker%.
Personally, I would probably make significant changes to your code. But I believe the following minimal changes can make your code work, assuming there are no other bugs:
enable delayed expansion
Move your DO loop code to a routine outside of the loop, and then have the loop CALL that routine with %%a as a parameter. CALL does not break the loop.
Substitute %1 for %%a in the routine
Substitute exit /b for goto endLoop. Also put exit /b at end of the routine
Make sure the code does not fall into the routine when the FOR loop finishes. I used a GOTO after the FOR loop
Substitute !checker! for %checker%
EDIT -The ) in the ECHO statement must be escaped
Here is the modified code (untested)
setlocal enableDelayedExpansion
set checker=0
for %%a in (%namelist%) do call :startLoop %%a
goto continue
:startLoop
findstr "completed" %1_Logs.txt
IF ERRORLEVEL 1 (
IF !checker!==120 (
set checker=0
exit /b
)
set /a checker=checker+1
#ping 127.0.0.1 -n 1 -w 1000 > nul
findstr "ERROR" %1_Logs.txt
IF ERRORLEVEL 1 (
echo Waiting 1 second before rechecking (Max 2 mins^)
echo time elapsed !checker! seconds
echo.
goto startLoop
)
findstr "ERROR" %1_Logs.txt
IF NOT ERRORLEVEL 1 (
echo ERROR: %1 Error found
exit /b
)
)
findstr "completed" %1_Logs.txt
IF NOT ERRORLEVEL 1 (
echo %1 completed
)
exit /b
:continue
I think the labels inside your for loop are messing it up. I just tried it moving the contents of the loop into a separate "subroutine" and that gets rid of the error you mention.
Try this:
set checker=0
for %%a in (foo bar baz) do (
call :loop %%a
)
goto :eof
:loop
set basename=%1
:startLoop
findstr "completed" %basename%_Logs.txt
IF ERRORLEVEL 1 (
IF %checker%==120 (
set checker=0
goto endLoop
)
set /a checker=%checker%+1
#ping 127.0.0.1 -n 1 -w 1000 > nul
findstr "ERROR" %basename%_Logs.txt
IF ERRORLEVEL 1 (
echo Waiting 1 second before rechecking (Max 2 mins)
echo time elapsed %checker% seconds
echo.
goto startLoop
)
findstr "ERROR" %basename%_Logs.txt
IF NOT ERRORLEVEL 1 (
echo ERROR: %basename% Error found
goto endLoop
)
)
findstr "completed" %basename%_Logs.txt
IF NOT ERRORLEVEL 1 (
echo %basename% completed
)
:endLoop
goto :eof

Resources