Narnian12
Narnian12

Reputation: 157

Weird behavior for nested labels in batch script

Here is the batch program:

@echo off
SETLOCAL EnableDelayedExpansion
set /a incr=0

set arg1=%1
del test_output.csv > NUL 2>&1
del test_output.log > NUL 2>&1

set startTime=%time%
for /d %%i in ("%cd%\*") do call :run_test "%%i"
.\log_parser.exe
type test_output.csv
echo Start Time: %startTime%
echo Finish Time: %time%
exit /B

:run_test
  if not "%~nx1" == "shared" (
    echo Test: %~nx1
    cd %1

    del pass_fail_output.csv > NUL 2>&1
    echo Running...
    cd temp_root_fs
    start application.exe
    set /a incr=0
    :while1
      tasklist /fi "IMAGENAME eq application.exe" 2>NUL | find /i /n "application.exe">NUL
      if "%ERRORLEVEL%"=="0" (
        if %incr% leq 60 (
          echo Still running...
          timeout /t 1 > NUL 2>&1
          set /a incr+= 1
          goto :while1
        )
        echo Test timed out...
        taskkill /im application.exe /f
      )
      echo Test completed...
    cd logs
    .\pass_fail_parser.exe
    type log.log >> ..\..\..\test_output.log
    copy pass_fail_output.csv ..\..\
    cd ..\..\
  )

  echo Cleaning...
  rmdir /S /Q temp_root_fs
  cd ..
)

This is my expected execution:

The first loop works fine, but this is what my current output looks like when I execute it:

Test: test1
Initializing...
Running...
Still running...
Still running...
Still running...
Still running...
Still running...
Still running...
Still running...
Still running...
Still running...
Still running...
Test completed...
        1 file(s) copied.
Cleaning...

I know this is not working properly because I have 3 more folders for tests, so it should continue on to the other folders, but somehow it seems to break out of the for loop early.

I have read about the /I option that supposedly prevents the goto from breaking out of iff and do loops, but I am not entirely sure how it works (I tried adding it as a parameter but it either errors out or does not seem to do anything).

Any help would be greatly appreciated!

Upvotes: 1

Views: 142

Answers (1)

Magoo
Magoo

Reputation: 80211

:run_test
  if not "%~nx1" == "shared" (
    echo Test: %~nx1
    cd %1

    del pass_fail_output.csv > NUL 2>&1
    echo Running...
    cd temp_root_fs
    start application.exe
    set /a incr=0

    CALL :while1

    echo Test completed...
    cd logs
    .\pass_fail_parser.exe
    type log.log >> ..\..\..\test_output.log
    copy pass_fail_output.csv ..\..\
    cd ..\..\
  )

  echo Cleaning...
  rmdir /S /Q temp_root_fs
  cd ..
)

GOTO :EOF

:while1
  tasklist /fi "IMAGENAME eq application.exe" 2>NUL | find /i /n "application.exe">NUL
  if "%ERRORLEVEL%"=="0" (
    if %incr% leq 60 (
      echo Still running...
      timeout /t 1 > NUL 2>&1
      set /a incr+= 1
      goto :while1
    )
    echo Test timed out...
    taskkill /im application.exe /f
  )

GOTO :EOF

In your code, if not "%~nx1" == "shared" ( to the final ) is a code block. Labels are not permitted within a code block. The values %var% are replaced when the if statement is parsed by the values of those variables at that time, not as the change due to actions executed within the block. Beware of the delayed expansion trap

The above code converts the :while1 loop to an internal subroutine invoked by CALL :while1 (the colon is required to indicate the call is to an internal label)

Note the GOTO :EOF statements. These transfer execution to the physical end-of-file (the colon is again, required) The first is to prevent execution from proceeding from :run_test into :while1 by flow-through. The second is to force a return to the statement following CALL :while1 when the :while1 routine finishes. The :while1 routine may be placed after any goto statement in the batch's mainline (ie. not a goto within a code block).

Upvotes: 2

Related Questions