Skip to content

Windows: The best way(s) to sleep or wait in a batch (cmd) script

October 26, 2011

UPDATE: This also works and is probably even better than  the conclusion the article comes to (the delay being the -w in msec):

ping -n 1 -w 2000 1.1.1.1 >NUL 2>&1

Here is the original article and conclusions:

For the longest time if you wanted to sleep in a batch script you either had to use a number of pings, call an outside program, or do some voodoo with a command like ‘choice’. Often times the solution is not reliable and/or not portable between Windows versions.

However I was just revisiting the issue and found a pretty impressive option (shown below) that uses only a conditional goto loop with some timestamps to determine if the correct amount of time has passed. Presumably, the accuracy of this option is roughly that of the system clock with a resolution of one second. The only source I have for this is a link to the stackoverflow.com page I saw it on: http://stackoverflow.com/questions/166044/sleeping-in-a-batch-file. The user who posted it there was “Aacini” but I am not sure if he/she was the original author.

The only real problem with the solution that I can see is that it pegs the CPU. In a virtual machine with a single 2.0ghz core, it easily forces 100% use for the duration of the delay. This is really only a problem if there are other things on the host that are getting slowed down by the delay code (which is likely). So, I’ve mixed it with the old ping solution to get the best of both worlds. Each pass of the goto loop issues two pings to localhost, which blocks the script for around one second each time. By doing this, the loop is slowed considerably and CPU utilization stays below 10%.

There are a few downsides to the change. The first is that if for some reason all of the ping commands terminate immediately, the delay will work as before and will likely cause very high CPU usage. The other is that if something happens to make each ping take longer (perhaps a completely shot network stack), you could be delayed for longer than intended.

I’ve done some testing and although it is usually accurate to within one second for any delay length, trying to use short delays of <=5 seconds is possibly less accurate. However for delays of 10 seconds or longer, the delay has (so far) been within one second of the correct delay 100% of the time. I would estimate the absolute worst case for any delay over 15 seconds would show 4 additional seconds elapsing. So 104 instead of 100, 79 instead of 75, etc., etc. Note that the loop will continue as long as the target time has not been found, so it shouldn’t be possible to get a shorter than expected delay…only a slightly longer one.

The upside here is that it works on XP and Win7 (and probably others that I haven’t tried), it makes no calls to outside programs, and it doesn’t eat up the CPU too much. If the CPU load isn’t an issue for you, be sure and use the version without the ping line in there!

@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
ping 127.0.0.1 -n 2 > nul
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

P.S.: batch’s for loops are hard to read… Generally speaking it is just getting the start time and converting it to seconds (since the start of each day), and then running a loop of ping+checking the time (again, in seconds) before continuing. The ‘%1’ on the end of the 5th line (ignoring word wrap) is where the delay goes. Normally you’ll save this in a file such as ‘delay.bat’ and then call ‘delay.bat 15’ to sleep for 15 seconds. You can remove the %1 and put a number after the ‘+’ to always sleep for that length, at which point you could drop this whole thing into another script. There may be modifications needed to delay across midnight from one day to another, which I believe is addressed on the stackoverflow page I linked.

Advertisements
No comments yet

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: