1

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:

  • Loop through folders
  • Run the application
  • Wait for 60 seconds and either kill the application after 60 seconds passes or continue if the application finishes
  • Do some other executions to port log messages into an overall log file

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!

Narnian12
  • 117
  • 1
  • 8
  • I think including the actual batch contents would help. Do you mean that `goto :while1` is ignored? Are you by chance calling another batch file? – Andrew Feb 25 '21 at 13:47
  • Thanks for the comment! I added a bit more code. I realized it might be because I'm trying to use the label to potentially call a `taskkill` for an executable I'm running – Narnian12 Feb 25 '21 at 13:52
  • So what is the last line that is executed? Did you try without the `@echo off` to clearly see what is executed? – Andrew Feb 25 '21 at 14:00
  • You have a [delayed expansion problem](https://stackoverflow.com/questions/30282784/variables-are-not-behaving-as-expected/30284028#30284028), but you can avoid it with `if not errorlevel 1 goto :while1`. Every `goto` breaks the command block. There is nothing (especially no `/i`) to avoid that (and breaking the block isn't a problem with your code, as far as you have shown it). – Stephan Feb 25 '21 at 14:00
  • Are you still missing lines? I get an error with `if defined run` (it expects the action after the condition), but even if that works for you, you are never undefining `run`. Are the quotes necessary in `"run=y"`? Why not just an `exit /b` after `taskkill`? If the application properly closes, you still get the timeout message and try to kill it. – Andrew Feb 25 '21 at 14:13
  • @Andrew: `set "var=value"` is best practice; it avoids unwanted spaces and is safe against poison chars. – Stephan Feb 25 '21 at 14:16
  • I added several more lines. I forgot that I am using `SETLOCAL EnableDelayedExpansion` but I might not be using it properly (I think I need to do `!var!` instead of `%var%`). The primary problem is that the `:while1` label seems to break the outside for loop as well. – Narnian12 Feb 25 '21 at 14:26
  • 1
    `I think I need to do !var! instead of %var%` - correct. `The primary problem is that the :while1 label seems to break the outside for loop as well` - correct. Goto breaks *all* code blocks/loops With the now shown code, this *is* a problem. (The link you provided in your question is about another language, so the commands/parameters may behave different than `cmd`) – Stephan Feb 25 '21 at 14:30
  • In my case the loop itself works fine (using the previous simplified batch code). I think you first need to clearly identify where the issue is. What I would do is: replace `application.exe` with something like `notepad.exe`, change the `start` with `echo start notepad.exe` and you just manually open one Notepad to avoid multiple annoying windows, use `leq 5` (or the like) instead, and also add an `echo` before `taskkill`. This way, you will verify that the whole logic goes though all the folders and waits 5 seconds. Finally, the `set /a incr=0` at line 3 can be removed. – Andrew Feb 25 '21 at 14:45
  • Thanks Andrew, I tried it out. It seems like what @Stephan said is what is happening: when I execute the `goto` at any point, it ultimately breaks all loops. – Narnian12 Feb 25 '21 at 15:41
  • 1
    There is no `/I` option for `goto`, nor are there `iff` or `do loops`. That's TCC, not `cmd`. – Magoo Feb 25 '21 at 16:21

1 Answers1

2
: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).

Magoo
  • 77,302
  • 8
  • 62
  • 84