3

I'm trying to make a very simple bat-file.

In a for-loop I call another application which will create a file for me. When that file is generated I want to do this again until the loop has finished. I need to wait for the file to be created before I run the loop again.

I need to use START and CALL, because after the file is created I will kill the process. It's not included in the code below, but it's needed.

@echo off

for /L %%i in (1,1,5) do (
    SET filename=fooFile_%%i.txt
        START /B CMD /C CALL createFile.bat fooFile_%%i.txt

    :waitfile
        ECHO waitforfile: %filename%
        TIMEOUT /T 10 >nul
        IF EXIST %filename% GOTO FoundIt
        goto waitfile

    :FoundIt
        ECHO Found file %filename%
)
ECHO All done!

And my createFile.bat. This is actually another application. But the code below is enough to mock it:

@echo off

set arg1=%1
TIMEOUT /T 10 >nul
copy NUL %arg1%
ECHO Created file

Current output:

waitforfile:
waitforfile fooFile_1.txt
    1 file(s) copied.
Created file
Found file fooFile_1.txt
All done!

As you can see from the output I can't get the loop to work with my GOTO's. I've seen these questions:

Batch file goto not working in for loop

(Windows batch) Goto within if block behaves very strangely

It seems as it's a bad idéa to combine loops with goto's. So how can I solve my problem?

2
  • There are two issues in your code: 1. you missed to use delayed expansion although it was required as you write and read the same variable within a block of code; 2. goto :Label cannot be used within a block/loop as this breaks the block/loop context;
    – aschipfl
    Commented Nov 30, 2016 at 9:57
  • @aschipfl - Thank you. I'm new to bat-files. I will try the suggested solutions. It seems as they all work. I just need to decide which solution that suits my specific problem best before I accept it as an answer.
    – smoksnes
    Commented Nov 30, 2016 at 10:15

3 Answers 3

3
  1. To use variables that may be changed in loops use EnableDelayedExpansion and !var! instead of %var%

  2. Move :waitfile to a sub

@echo off
setlocal EnableDelayedExpansion

for /L %%i in (1,1,5) do (
    SET filename=fooFile_%%i.txt
        START /B CMD /C CALL createFile.bat fooFile_%%i.txt

    call :waitfile "!filename!"

    ECHO Found file !filename!
)
ECHO All done!
exit /b 0

:waitfile
    ECHO waitforfile: %~1
:waitfile2
    TIMEOUT /T 10 >nul
    IF not EXIST "%~1" goto waitfile2
exit /b 0
1
  • Thanks! Accepted this particular answer since it suited my needs best and it was a good fit with my other logic. The other answers worked as well.
    – smoksnes
    Commented Nov 30, 2016 at 11:47
3
@echo off
    setlocal enableextensions disabledelayedexpansion

    for /L %%i in (1,1,5) do for %%f in ("fooFile_%%i.txt") do (
        start /b "" cmd /c createFile.bat "%%~ff" 

        2>nul ( 
            break | for /l %%a in (0) do @(<"%%~ff" exit) || ( 
                echo ...waiting for %%~ff
                ping -n 5 localhost >nul 
            ) 
        )

        echo [%%~ff]  found
    )
    ECHO All done!
  • To avoid enabling delayed expansion only to retrieve the value inside the changed variable, the generated file name is wrapped inside a for replaceable parameter (%%f)

  • The wait loop is executed in a separate cmd process (spawned to handle the pipe) that will end when the target file can be read. If the file is not available the <"%%~ff" input redirection will fail and the exit command will not be executed. If the file is available, then the exit command is executed and the loop ends.

  • As timeout can not be used with a redirected input (wait code is running inside a pipe), it has been replaced with a ping to local host

  • This test code uses full paths for generated files (%%~ff is the full path of the file being pointed by %%f). Change it to your needs.

note: just for reference, the createFile.bat used for testing was

@echo off
    setlocal enableextensions disabledelayedexpansion

    if "%~1"=="" exit /B
    >nul timeout /t 3
    >"%~1" echo testing
1
@echo off

for /L %%i in (1,1,5) do (call :process %%i
)
ECHO All done!

:: rest of mainline code here

goto :eof

:process
    SET filename=fooFile_%1.txt
    START /B CMD /C CALL createFile.bat fooFile_%1.txt

:waitfile
    ECHO waitforfile: %filename%
    TIMEOUT /T 10 >nul
    IF EXIST %filename% GOTO FoundIt
    goto waitfile

:FoundIt
    ECHO Found file %filename%
    goto :eof

There are other problems with your batch - mainly delayedexpansion methodology is required if you use the changed value of an environment variable in the loop.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.