Things I've Learned

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

Published Sunday, February 26, 2006 2:08 AM by threekings

Comments

 

threekings said:

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
June 13, 2006 7:11 PM
 

The Old New Thing said:

And its logical consequences.
August 23, 2006 10:00 AM
 

jgurtz said:

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!

July 23, 2009 3:46 PM
Anonymous comments are disabled

© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker