Reputation: 10851
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?
Upvotes: 3
Views: 6570
Reputation: 79983
@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.
Upvotes: 1
Reputation: 3180
To use variables that may be changed in loops use EnableDelayedExpansion
and !var!
instead of %var%
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
Upvotes: 3
Reputation: 70923
@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
Upvotes: 3