我正在尝试为文件夹中的每个文件执行一些操作,等到虚拟机的属性设置为特定值并执行一些其他任务:
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
这段代码输出
"doing some task"
并继续做其他事情(我的意思是它不打印任何其他内容并且不停止),如何解决这个问题?
更新: 对 Mofi 的一些说明:我需要在所有迭代中等待
STATE
属性 - 该属性意味着我的脚本在来宾虚拟机中完成。所以,如果我在目标文件夹中有 2 个文件,批处理文件应该执行类似的操作:
STATE
属性设置为“Finished”(迭代 2)
STATE
变量应该被清除)STATE
属性设置为“完成”check_state
子例程返回到外部 FOR
循环。
注意:我已经修复了缺失的 setlocal enabledelayedexpansion
线。更新2:我厌倦了处理批处理,所以我使用Python重写了我的脚本。但是,我仍然有兴趣了解如何使用批处理文件来完成此操作。
也许可以使用以下代码:
@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
代码期望子例程中的 FOR 在后台执行以下命令行
wait_for_state
总是在几毫秒内快速完成:
C:\Windows\System32\cmd.exe /c VBoxManage guestproperty get "Win10-Pro-x32" "State"
命令 FOR 始终等待启动的
cmd.exe
的自终止,该自终止在执行 VBoxManage
(可执行文件或脚本)后自行关闭。然后 FOR 处理通过 VBoxManage
写入后台命令进程句柄 STDOUT(标准输出)的捕获输出。
IF 条件 if not "%State:Finished=%" == "%State%" exit /B 0
将分配给环境变量
State
的字符串替换为空字符串(不区分大小写)所有出现的单词
Finished
(删除该单词),并将结果字符串与分配的未修改字符串进行比较到环境变量
State
。仅当分配给环境变量
State
的字符串包含不区分大小写的至少一次单词
Finished
时,两个比较的字符串才不相等,在这种情况下,子例程将以值 0 退出以继续处理批处理文件在命令行下方
call :wait_for_state
。我通过在当前目录中创建第二个批处理文件来测试批处理文件,其名称为
VBoxManage.cmd
,仅包含以下命令行:
@if exist test.txt del test.txt & echo ... Finished ...
我在上面的批处理文件运行时打开了第二个命令提示符窗口,并以当前目录作为包含两个批处理文件的目录执行命令echo Test>Test.txt
,以测试子例程的两个退出条件。要了解所使用的命令及其工作原理,请打开
命令提示符窗口,执行以下命令,并完整、仔细地阅读每个命令显示的帮助页面。
call /?
echo /?
endlocal /?
exit /?
goto /?
if /?
set /?
setlocal /?