errorlevel in for loop returns exit code of iterating statement


It turns out that errorlevel is returning the exit code of iterating statement in the for loop instead of the one immediately preceding it.


for /r \\computer\share\x86 %%x in (*.xml) do (


    IsVarMap.exe /file:"%%x"


    echo %ERRORLEVEL%


)


Echoes 0 always. I expect some iterations to return 2, when xml file isn’t a VarMap.



IsVarMap.exe /file:notavarmap.xml


echo %ERRORLEVEL%



Echoes 2 as expected


Comments (4)
  1. WTF Chuck says:

    This behavior actually makes the FOR /L construct unusable except in trivial cases.  the setlocal enabledelayedexpansion will only work in some cases as well (a subshell seems to break it) and even the :: comment char seems to break inside a for loop.

    I was writing a startup script to handle startup service dependencies that a couple foreground apps have and I thought nice we have a real for loop construct in cmd files in XP/2003!  Alas, the following doesn’t work:

    SET PS=powershell -nologo -command

    SET Sleep=timeout /nobreak /t

    setlocal enabledelayedexpansion

    FOR /L %%i (1,1,5) DO (

       SET SVC=MSSQLSERVER

       %PS% "& {if((get-service %SVC%).Status -eq ‘Running’) {Exit 1}}" > NUL

       IF !ERRORLEVEL! EQU 1 GOTO :NextTest

       ECHO.  Sleeping 5 seconds…

       %Sleep% 5 2>&1> NUL

    )

    endlocal

    REM Woopsie, never get here ’cause we loop forever since %%i goes undefined

    GOTO :ServiceStartupTimeout

    :NextTest

    REM Woopsie, we get here one loop late if %SVC% is Running  This is because %%i goes undefined

    REM after a subshell is used. When %%i is undef, then %ERRORLEVEL% and !ERRORLEVEL! == 1

    REM Note this makes the service testing useless because we always escape the loop even if the service isn’t

    REM running.

    :ServiceStartupTimeout

    ECHO.Timed out waiting for services to start.

    GOTO :EOF

    :EOF

    The above problems are all fixed when you enclose the testing inside a SET /A construct like this:

    @ECHO off

    SET i=0

    SET iMax=12

    :TestSQL

       SET SVC=MSSQLSERVER

       %PS% "& {if((get-service %SVC%).Status -eq ‘Running’) {Exit 1}}" > NUL

       IF !ERRORLEVEL! EQU 1 GOTO :NextTest    

       IF %i% == %iMax% GOTO :TestSQL_End

       SET /A i=%i% + 1

       ECHO.  Sleeping 5 seconds…

       %Sleep% 5 2>&1> NUL

       GOTO :TestSQL

    :TestSQL_End

    GOTO :ServiceStartupTimeout

    :NextTest

    Makes one wonder, why not just use powershell for the whole thing eh?  Of course they could just fix sc query so contortions aren’t necc. to get a service status!

  2. Anonymous says:

    And its logical consequences.

  3. threekings says:

    This may explain why this happens and how to work around it:

    From Mark Yocom:

    Actually, you can nest for loops all you like.  The kicker is that if you set a variable inside the for loop and then try to access that variable from within the loop, it won’t work like you might expect.  Instead, you can use ‘setlocal enabledelayedexpansion’ and refer to your variable as !VAR!.  For example:

    Doesn’t work

    @echo off

    for %%x in (foo bar baz) do (

       set VAR=%%x

       echo %VAR%

    )

    Works

    @echo off

    setlocal enabledelayedexpansion

    for %%x in (foo bar baz) do (

       set VAR=%%x

       echo !VAR!

    )

    endlocal

  4. pete says:

    for /r \computersharex86 %%x in (*.xml) do (CALL :ISVARMAP "%%x")
    exit
    :ISVARMAP
    IsVarMap.exe /file:"%~1"
    echo %ERRORLEVEL%
    goto :EOF

Comments are closed.

Skip to main content