Reputation: 1275
I'm trying to do some job for every file in a folder, wait until a property of virtual machine is set to a specific value and do some other tasks:
ECHO off
setlocal enabledelayedexpansion
SET VM_NAME=Win10-Pro-x32
SET TESTS_FOLDER=C:\tests
SET STATE=
SET FINISHED_STATE=Finished
FOR %%f IN (%TESTS_FOLDER%\*) DO (
echo "doing some task"
:checking_loop
IF !STATE! NEQ !FINISHED_STATE! call :check_state
echo "doing some other task"
)
goto :eof
:check_state
FOR /f "tokens=*" %%i IN ('VBoxManage guestproperty get %VM_NAME% "State"') DO SET STATE=%%i
SET STATE=%STATE:~7%
ping 127.0.0.1 -n 2 > nul
goto :checking_loop
This code outputs "doing some task"
and continue doing something else (I mean it not prints anything else and not stops), how to fix that?
UPDATE: Some clarifications for Mofi: I need to wait for STATE
property in all iterations - this property means that my script finished in guest VM. So, if I have 2 files in target folder batch file should do something like that:
STATE
property to "Finished"(Iteration 2)
STATE
variable should be cleared)STATE
property to "Finished"check_state
subroutine back to outside FOR
loop.
Note: I had fixed the missing setlocal enabledelayedexpansion
line.UPDATE 2: I had tired to deal with batch, so I rewrote my script using Python. However, I still interested to get how to do it using batch file.
Upvotes: 0
Views: 51
Reputation: 49086
There could be perhaps used the following code:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "VM_NAME=Win10-Pro-x32"
set "TESTS_FOLDER=C:\tests"
if exist %SystemRoot%\System32\timeout.exe (
set "WaitASecond=%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK"
) else (
set "WaitASecond=%SystemRoot%\System32\ping.exe -n 2 -w 1000 127.0.0.1"
)
for %%I in ("%TESTS_FOLDER%\*") do (
echo doing some task
call :wait_for_state
if not errorlevel 1 (
echo doing some other task
) else (
echo Do something on state Finished not returned within 60 retries.
)
)
rem Exit the batch file processing without a fall through to the subroutine.
exit /B
rem The subroutine below exits with value 0 on executed program/script has
rem output a string containing anywhere case-insensitive the word Finished.
rem The program/script is otherwise executed after a delay of one second
rem once more. But the retry loop is exited after 60 retries which is
rem approximately 60 seconds (one minute) on VBoxManage finishes always
rem quickly in a few milliseconds to avoid an endless running retry loop.
rem The value 1 is returned in this error case by the subroutine to the
rem calling FOR loop above which should handle this error case appropriately.
:wait_for_state
set "State=Wait"
set "LoopCount=60"
:Retry
for /F "tokens=*" %%J in ('VBoxManage guestproperty get "%VM_NAME%" "State"') do set "STATE=%%J"
if not "%State:Finished=%" == "%State%" exit /B 0
set /A LoopCount-=1
if %LoopCount% == 0 exit /B 1
%WaitASecond% >nul
goto Retry
The code expects that the execution of the following command line in background by FOR inside the subroutine wait_for_state
finishes always quickly in a few milliseconds:
C:\Windows\System32\cmd.exe /c VBoxManage guestproperty get "Win10-Pro-x32" "State"
The command FOR always waits for self-termination of started cmd.exe
which closes itself after execution of VBoxManage
(executable or script). Then FOR processes the captured output written to the handle STDOUT (standard output) of the background command process by VBoxManage
.
The IF condition if not "%State:Finished=%" == "%State%" exit /B 0
replaces in string assigned to the environment variable State
case-insensitive all occurrences of the word Finished
by an empty string (remove that word) and compares the resulting string with the unmodified string assigned to the environment variable State
. The two compared strings are only not equal if the string assigned to the environment variable State
contains case-insensitive indeed at least once the word Finished
in which case the subroutine is exited with value 0 to continue the processing of the batch file below the command line call :wait_for_state
.
The batch file was tested by me by creating in current directory a second batch file with name VBoxManage.cmd
containing just the following command line:
@if exist test.txt del test.txt & echo ... Finished ...
I opened a second command prompt window while the batch file above was running and executed with current directory being the directory containing the two batch files from time to time the command echo Test>Test.txt
to test both exit conditions of the subroutine.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
call /?
echo /?
endlocal /?
exit /?
goto /?
if /?
set /?
setlocal /?
Upvotes: 2