循环的批处理脚本不起作用

时间:2012-11-14 00:25:25

标签: windows command-line batch-file

我需要让多个远程管理员在网站上测试他们的下载速度。 Speedtest.net等都不是我们广域网性能的真正指标。我不希望使用iperf,因为我需要尽量减少远程管理员的技术知识和工作量。我不希望他们也要安装任何东西。因此,我需要一个简单的批处理文件来下载测试文件5次。这就是我到目前为止所做的:

@echo off
rem localize variables to this script
setlocal
rem delete the test file if it already exists
if exist %HomePath%\Downloads\100meg.test del %HomePath%\Downloads\100meg.test
rem perform the test 5 times
for /l %%i IN (1,1,5) DO (
    rem mark the start time
    set STARTTIME=%TIME%
    echo Download started at:%STARTTIME%
    rem start download
    C:\windows\explorer.exe http://mirror.internode.on.net/pub/test/100meg.test
    rem check for file download completion
    :while
        if exist %HomePath%\Downloads\100meg.test goto wend
        goto while
    :wend
    rem mark the end time
    set ENDTIME=%TIME%
    echo Download completed at:%ENDTIME%
    rem convert STARTTIME and ENDTIME to centiseconds
    set /A STARTTIME=(1%STARTTIME:~0,2%-100)*360000 + (1%STARTTIME:~3,2%-100)*6000 + (1%STARTTIME:~6,2%-100)*100 + (1%STARTTIME:~9,2%-100)
    set /A ENDTIME=(1%ENDTIME:~0,2%-100)*360000 + (1%ENDTIME:~3,2%-100)*6000 + (1%ENDTIME:~6,2%-100)*100 + (1%ENDTIME:~9,2%-100)
    rem calculate the time taken in seconds
    set /A DURATION=(%ENDTIME%-%STARTTIME%)/100
    echo Download took:%DURATION% seconds
    rem delete the test file ready for next iteration
    del %HomePath%\Downloads\100meg.test
)

问题在于,因为在括号中添加for并将块封闭,所以它停止工作。任何人都可以解释为什么会失败吗?

谢谢!

1 个答案:

答案 0 :(得分:3)

在FOR循环中使用GOTO总是会中断循环 - 使用GOTO后不会发生剩余的迭代。

这是因为CMD.EXE的工作方式。括号内的整个命令块被解析并一次性加载到内存中。每次迭代都会执行存储在内存中的已解析命令。这些解析的命令不包含任何标签。 GOTO必须扫描文件,这需要打破循环。

STARTTIME的“消失”值也与整个块一次解析的事实有关。 %STARTTIME%在解析时扩展,但在执行任何块之前解析该命令。因此,您将获得执行FOR命令之前存在的值,这可能是未定义的。有一个称为延迟扩展的功能,可用于在执行时获取变量的值而不是解析时间。从命令提示符处键入HELP SET,并阅读有关延迟扩展的部分,该部分从文档的一半开始。

但是有一种简单的方法可以使代码工作 - 只需将DO块的内容移动到子程序,然后在循环中调用例程。 (我假设您在DO子句中的逻辑是正确的)。 CALL不会破坏循环: - )

您必须记住在例程标签之前放置一个EXIT / B,这样您的主代码就不会落入子程序。

@echo off
rem localize variables to this script
setlocal
rem delete the test file if it already exists
if exist %HomePath%\Downloads\100meg.test del %HomePath%\Downloads\100meg.test
rem perform the test 5 times
for /l %%i IN (1,1,5) do call :downloadTest
exit /b

:downloadTest
rem mark the start time
set STARTTIME=%TIME%
echo Download started at:%STARTTIME%
rem start download
C:\windows\explorer.exe http://mirror.internode.on.net/pub/test/100meg.test
rem check for file download completion
:while
  if exist %HomePath%\Downloads\100meg.test goto wend
  goto while
:wend
rem mark the end time
set ENDTIME=%TIME%
echo Download completed at:%ENDTIME%
rem convert STARTTIME and ENDTIME to centiseconds
set /A STARTTIME=(1%STARTTIME:~0,2%-100)*360000 + (1%STARTTIME:~3,2%-100)*6000 + (1%STARTTIME:~6,2%-100)*100 + (1%STARTTIME:~9,2%-100)
set /A ENDTIME=(1%ENDTIME:~0,2%-100)*360000 + (1%ENDTIME:~3,2%-100)*6000 + (1%ENDTIME:~6,2%-100)*100 + (1%ENDTIME:~9,2%-100)
rem calculate the time taken in seconds
set /A DURATION=(%ENDTIME%-%STARTTIME%)/100
echo Download took:%DURATION% seconds
rem delete the test file ready for next iteration
del %HomePath%\Downloads\100meg.test
exit /b