Sleeping in a batch file

2019-01-01 13:10发布

When writing a batch file to automate something on a Windows box, I've needed to pause its execution for several seconds (usually in a test/wait loop, waiting for a process to start). At the time, the best solution I could find uses ping (I kid you not) to achieve the desired effect. I've found a better write-up of it here, which describes a callable "wait.bat", implemented as follows:

@ping 127.0.0.1 -n 2 -w 1000 > nul
@ping 127.0.0.1 -n %1% -w 1000> nul

You can then include calls to wait.bat in your own batch file, passing in the number of seconds to sleep.

Apparently the Windows 2003 Resource Kit provides a Unix-like sleep command (at last!). In the meantime, for those of us still using Windows XP, Windows 2000 or (sadly) Windows NT, is there a better way?

I modified the sleep.py script in the accepted answer, so that it defaults to one second if no arguments are passed on the command line:

import time, sys

time.sleep(float(sys.argv[1]) if len(sys.argv) > 1 else 1)

30条回答
明月照影归
2楼-- · 2019-01-01 13:29

I like Aacini's response. I added to it to handle the day and also enable it to handle centiseconds (%TIME% outputs H:MM:SS.CC):

:delay
SET DELAYINPUT=%1
SET /A DAYS=DELAYINPUT/8640000
SET /A DELAYINPUT=DELAYINPUT-(DAYS*864000)

::Get ending centisecond (10 milliseconds)
FOR /F "tokens=1-4 delims=:." %%A IN ("%TIME%") DO SET /A H=%%A, M=1%%B%%100, S=1%%C%%100, X=1%%D%%100, ENDING=((H*60+M)*60+S)*100+X+DELAYINPUT
SET /A DAYS=DAYS+ENDING/8640000
SET /A ENDING=ENDING-(DAYS*864000)

::Wait for such a centisecond
:delay_wait
FOR /F "tokens=1-4 delims=:." %%A IN ("%TIME%") DO SET /A H=%%A, M=1%%B%%100, S=1%%C%%100, X=1%%D%%100, CURRENT=((H*60+M)*60+S)*100+X
IF DEFINED LASTCURRENT IF %CURRENT% LSS %LASTCURRENT% SET /A DAYS=DAYS-1
SET LASTCURRENT=%CURRENT%
IF %CURRENT% LSS %ENDING% GOTO delay_wait
IF %DAYS% GTR 0 GOTO delay_wait
GOTO :EOF
查看更多
看淡一切
3楼-- · 2019-01-01 13:29

The usage of ping is good, as long as you just want to "wait for a bit". This since you are dependent on other functions underneath, like your network working and the fact that there is nothing answering on 127.0.0.1. ;-) Maybe it is not very likely it fails, but it is not impossible...

If you want to be sure that you are waiting exactly the specified time, you should use the sleep functionality (which also have the advantage that it doesn't use CPU power or wait for a network to become ready).

To find an already made executable for sleep is the most convenient way. Just drop it into your Windows folder or any other part of your standard path and it is always available.

Otherwise, if you have a compiling environment you can easily make one yourself. The Sleep function is available in kernel32.dll, so you just need to use that one. :-) For VB / VBA declare the following in the beginning of your source to declare a sleep function:

private Declare Sub Sleep Lib "kernel32" Alias "Sleep" (byval dwMilliseconds as Long)

For C#:

[DllImport("kernel32.dll")]
static extern void Sleep(uint dwMilliseconds);

You'll find here more about this functionality (available since Windows 2000) in Sleep function (MSDN).

In standard C, sleep() is included in the standard library and in Microsoft's Visual Studio C the function is named Sleep(), if memory serves me. ;-) Those two takes the argument in seconds, not in milliseconds as the two previous declarations.

查看更多
梦该遗忘
4楼-- · 2019-01-01 13:29

You can get fancy by putting the PAUSE message in the title bar:

@ECHO off
SET TITLETEXT=Sleep
TITLE %TITLETEXT%
CALL :sleep 5
GOTO :END
:: Function Section
:sleep ARG
ECHO Pausing...
FOR /l %%a in (%~1,-1,1) DO (TITLE Script %TITLETEXT% -- time left^
 %%as&PING.exe -n 2 -w 1000 127.1>NUL)
EXIT /B 0
:: End of script
:END
pause
::this is EOF
查看更多
步步皆殇っ
5楼-- · 2019-01-01 13:30

I am impressed with this one:

http://www.computerhope.com/batch.htm#02

choice /n /c y /d y /t 5 > NUL

Technically, you're telling the choice command to accept only y. It defaults to y, to do so in 5 seconds, to draw no prompt, and to dump anything it does say to NUL (like null terminal on Linux).

查看更多
不流泪的眼
6楼-- · 2019-01-01 13:30

You can use ping:

ping 127.0.0.1 -n 11 -w 1000 >nul: 2>nul:

It will wait 10 seconds.

The reason you have to use 11 is because the first ping goes out immediately, not after one second. The number should always be one more than the number of seconds you want to wait.

Keep in mind that the purpose of the -w is not to wait one second. It's to ensure that you wait no more than one second in the event that there are network problems. ping on its own will send one ICMP packet per second. It's probably not required for localhost, but old habits die hard.

查看更多
人间绝色
7楼-- · 2019-01-01 13:32

I disagree with the answers I found here.

I use the following method entirely based on Windows XP capabilities to do a delay in a batch file:

DELAY.BAT:

@ECHO OFF
REM DELAY seconds

REM GET ENDING SECOND
FOR /F "TOKENS=1-3 DELIMS=:." %%A IN ("%TIME%") DO SET /A H=%%A, M=1%%B%%100, S=1%%C%%100, ENDING=(H*60+M)*60+S+%1

REM WAIT FOR SUCH A SECOND
:WAIT
FOR /F "TOKENS=1-3 DELIMS=:." %%A IN ("%TIME%") DO SET /A H=%%A, M=1%%B%%100, S=1%%C%%100, CURRENT=(H*60+M)*60+S
IF %CURRENT% LSS %ENDING% GOTO WAIT

You may also insert the day in the calculation so the method also works when the delay interval pass over midnight.

查看更多
登录 后发表回答