How to store ERRORLEVEL in a variable? - batch-file

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.

Related

Batchfile: Problems to get errorlevel, it is always 0

scripters,
at first sorry for the last post.
Realy, i hope i could make you understand my problem now.
I realized that the problem is inside my script only.
If i run the line in the command prompt it works fine.
That means the Errorlevel is stored to exitCode.txt correctly.
START /B "some title" cmd /C "subroutine.bat& >"exitCode.txt" (call echo %^errorlevel%)& >"status.txt" (echo done) & (if defined return call echo %^return%) >"return.txt"" 1>"stdOut.txt" 2>"stdErr.txt"
This is a part of my script
So in :treath.run is the START /B .... line
Inside the script the errorlevel is not stored correctly inside the definded file.
Why?
The return Value is stored perfect.
I dont't get it.
Save this as main.bat
#echo off
setlocal ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
pushd "%~dp0"
:main
call :treath.import
call :treath.init "t1" "call subroutine.bat"
call :treath.run "t1"
:loop
call :treath.status "t1"
if "!return!"=="done" goto done
echo !return!
goto loop
:done
echo Now goto "!%t1%.stdExitCode!"
echo.
echo The Subroutine should return Errorlevel 1
echo But it is 0, in the file.
pause
EXIT
goto main
:::::::::::::::::::::::::::::::::::::::
:treath.import ()
set "return="
setlocal
set "objID=__OBJ_TREATH"
set "workdir=%tmp%\BATCH_OBJ\%objID%"
if not exist "%workdir%" (mkdir "%workdir%" || exit /b 1)
set /a "timeout=999"
:newSessionID
set /a "sessionID=%random%"
set "sessionDir=%workdir%\%sessionID%"
if exist "%sessionDir%" (
set /a "timeout-=1"
if !timeout! LSS 0 exit /b 1
goto newSessionID
)
mkdir "%sessionDir%" || exit /b 1
endlocal & (
rem set "%objID%_identifier=%objID%"
set "%objID%_version=0"
set "%objID%_sessionID=%sessionID%"
set "%objID%_sessionDir=%sessionDir%"
)
exit /b 0
:treath.init (treathName,"command")
set "return="
setlocal
rem hardcoded obj ident
set "objID=__OBJ_TREATH"
rem objID
set "prefix=%objID%_%~1"
rem treath folder
set "workdir=!%objID%_sessionDir!\%~1"
mkdir "%workdir%" || exit /b 1
set "command=%~2"
endlocal & (
set "%prefix%.command=%command%"
set "%prefix%.workdir=%workdir%"
set "%prefix%.stdOut=%workdir%\stdOut.txt"
set "%prefix%.stdErr=%workdir%\stdErr.txt"
set "%prefix%.stdDump=%workdir%\stdDump.txt"
set "%prefix%.stdExitCode=%workdir%\stdExitCode.txt"
set "%prefix%.return=%workdir%\return.txt"
set "%prefix%.stdStatus=%workdir%\stdStatus.txt"
set "%~1=%prefix%"
)
exit /b 0
:treath.run (treathName)
set "return="
setlocal
set "title=%~1"
set "prefix=!%~1!"
type NUL >"!%prefix%.stdExitCode!"
type NUL >"!%prefix%.stdOut!"
type NUL >"!%prefix%.stdErr!"
type NUL >"!%prefix%.stdStatus!"
rem errorlevel ist immer 0 ???
START /B "%title%" cmd /C "!%prefix%.command!& >"!%prefix%.stdExitCode!" (call echo %%^errorlevel%%)& >"!%prefix%.stdStatus!" (echo done) & (if defined return call echo %%^return%%) >"!%prefix%.return!"" 1>"!%prefix%.stdOut!" 2>"!%prefix%.stdErr!"
>"!%prefix%.stdStatus!" (echo running)
exit /b 0
:treath.status (treathName)
set "return="
setlocal
set "prefix=!%~1!"
endlocal & (
set /p "return="<"!%prefix%.stdStatus!" || exit /b 1
)
exit /b 0
Save this as "subroutine.bat"
set "return=This is a Test"
exit /b 1

Exit and re-enter loop in Windows batch file

I need to cycle through a list in a batch file, set a variable, exit the loop and then re-enter.
if "%scale%" == "ind" (
FOR %%A IN %inclpeople% do (
set person=%%A
goto :start
:cyclepeople
echo Done %person%
)
goto :end
)
set person=%scale%
:start
echo Starting with %person%
call %batch%\findperson
if %errorlevel% neq 0 goto :failed
call %batch%\dosomethingelse
if %errorlevel% neq 0 goto :failed
:finish
if "%scale%" == "ind" (
goto :cyclepeople
)
:end
call %footer%\success
exit /b 0
So, if scale is not "ind" (in this case it could be "all", then go to start and run commands only once. If scale equals "ind", then loop through a list of people, set person to loop variable, go to start and go back to loop until list is finished, then go to end.
Currently, this works only for the first loop and echos "Done Adam" (e.g. first person), but then goes to end.
For future reference, I will answer the question based on Stephan's comment above:
if "%scale%" == "ind" (
FOR %%A IN %inclpeople% do (
set person=%%A
call :start
echo Done %person%
)
goto :end
)
set person=%scale%
:start
echo Starting with %person%
call %batch%\findperson
if %errorlevel% neq 0 goto :failed
call %batch%\dosomethingelse
if %errorlevel% neq 0 goto :failed
:finish
if "%scale%" == "all" (goto :end)
goto :eof
:end
call %footer%\success
exit /b 0

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 do I reduce the codes require to check error

We check error using
if !ERRORLEVEL! NEQ 0 (do something)
but this is littered everywhere in the batch file.
1) Is the a way to encapsulate it to log and exit program upon error?
2) how do I log the bat file line number that is causing the error?
#ECHO OFF
SETLOCAL
ECHO y|FIND "y" >NUL
CALL aberr matching y and y
pause
ECHO x|FIND "y" >NUL
CALL aberr matching x and y
pause
ECHO y|FIND "z" >NUL
CALL aberr matching y and z
pause
GOTO :EOF
The above is a testing scenario, setting errorlevel to 0, 1, 1 in succession, then CALLing then batch aberr.bat to analyse the result.
Here's aberr.bat
#ECHO OFF
IF %ERRORLEVEL%==0 GOTO :EOF
ECHO %ERRORLEVEL% found %*
EXIT
Note here that there is no SETLOCAL (which would set ERRORLEVEL to zero) and that the routine EXITs.
Consequence is that if aberr.bat is on the PATH then the message produced would show the errorlevel found plus any text that was on the CALL aberr line after CALL aberr.
You could place a PAUSE after the ECHO %ERRORLEVEL% line to show the result, or log the result to a file by using
>>logfile.txt ECHO %ERRORLEVEL% found %*
at 1) How to log and exit the batch Exit from nested batch file
at 2) How to get the current line number?
Mix them and you get it.
setlocal EnableDelayedExpansion
cd. & REM *** Set the errorlevel to 0
if %errorlevel% NEQ 0 (
call :getLineNumber errLine uniqueID4711 -2
call :log ERROR: in line !errLine!
)
set /a n=0xGH 2> nul & REM Force the errorlevel to !=1
if %errorlevel% NEQ 0 (
call :getLineNumber errLine uniqueID4711 -2
call :log ERROR: in line !errLine!
)
echo all OK
exit /b
:log
>error.log echo %*
call :HALT
exit /b
:HALT
call :__halt 2> nul
exit /b
:__halt
()
:::::::::::::::::::::::::::::::::::::::::::::
:GetLineNumber <resultVar> <uniqueID> [LineOffset]
:: Detects the line number of the caller, the uniqueID have to be unique in the batch file
:: The lineno is return in the variable <resultVar> add with the [LineOffset]
SETLOCAL
for /F " usebackq tokens=1 delims=:" %%L IN (`findstr /N "%~2" "%~f0"`) DO set /a lineNr=%~3 + %%L
(
ENDLOCAL
set "%~1=%LineNr%"
goto :eof
)
Use something like:
...
if !ERRORLEVEL! NEQ 0 Call :LogAndExit "some explanation"
...
GoTo :EOF
:LogAndExit
Echo %Date% %Time% - %~1>>Log.txt
Exit /B

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