Home » Python » Sleeping in a batch file

Sleeping in a batch file

Posted by: admin November 1, 2017 Leave a comment

Questions:

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)
Answers:

If you have Python installed, or don’t mind installing it (it has other uses too :), just create the following sleep.py script and add it somewhere in your PATH:

import time, sys

time.sleep(float(sys.argv[1]))

It will allow sub-second pauses (for example, 1.5 sec, 0.1, etc.), should you have such a need. If you want to call it as sleep rather than sleep.py, then you can add the .PY extension to your PATHEXT environment variable. On Windows XP, you can edit it in:

My Computer → Properties (menu) → Advanced (tab) → Environment Variables (button) → System variables (frame)

Questions:
Answers:

The timeout command is available from Windows Vista onwards:

c:\> timeout /?

TIMEOUT [/T] timeout [/NOBREAK]

Description:
    This utility accepts a timeout parameter to wait for the specified
    time period (in seconds) or until any key is pressed. It also
    accepts a parameter to ignore the key press.

Parameter List:
    /T        timeout       Specifies the number of seconds to wait.
                            Valid range is -1 to 99999 seconds.

    /NOBREAK                Ignore key presses and wait specified time.

    /?                      Displays this help message.

NOTE: A timeout value of -1 means to wait indefinitely for a key press.

Examples:
    TIMEOUT /?
    TIMEOUT /T 10
    TIMEOUT /T 300 /NOBREAK
    TIMEOUT /T -1

Note: It does not work with input redirection – trivial example:

C:\>echo 1 | timeout /t 1 /nobreak
ERROR: Input redirection is not supported, exiting the process immediately.

Questions:
Answers:

Using the ping method as outlined is how I do it when I can’t (or don’t want to) add more executables or install any other software.

You should be pinging something that isn’t there, and using the -w flag so that it fails after that amount of time, not pinging something that is there (like localhost) -n times. This allows you to handle time less than a second, and I think it’s slightly more accurate.

e.g.

(test that 1.1.1.1 isn’t taken)

ECHO Waiting 15 seconds

PING 1.1.1.1 -n 1 -w 15000 > NUL
  or
PING -n 15 -w 1000 127.1 >NUL

Questions:
Answers:

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.

Questions:
Answers:

SLEEP.exe is included in most Resource Kits e.g. The Windows Server 2003 Resource Kit which can be installed on Windows XP too.

Usage:  sleep      time-to-sleep-in-seconds
        sleep [-m] time-to-sleep-in-milliseconds
        sleep [-c] commited-memory ratio (1%-100%)

Questions:
Answers:

I faced a similar problem, but I just knocked up a very short C++ console application to do the same thing. Just run MySleep.exe 1000 – perhaps easier than downloading/installing the whole resource kit.

#include <tchar.h>
#include <stdio.h>
#include "Windows.h"

int _tmain(int argc, _TCHAR* argv[])
{
    if (argc == 2)
    {
        _tprintf(_T("Sleeping for %s ms\n"), argv[1]);
        Sleep(_tstoi(argv[1]));
    }
    else
    {
        _tprintf(_T("Wrong number of arguments.\n"));
    }
    return 0;
}

Questions:
Answers:

Over at Server Fault, a similar question was asked, the solution there was:

choice /d y /t 5 > nul

Questions:
Answers:

You could use the Windows cscript WSH layer and this wait.js JavaScript file:

if (WScript.Arguments.Count() == 1)
    WScript.Sleep(WScript.Arguments(0)*1000);
else
    WScript.Echo("Usage: cscript wait.js seconds");

Questions:
Answers:

Depending on your compatibility needs, either use ping:

ping -n <numberofseconds+1> localhost >nul 2>&1

e.g. to wait 5 seconds, use

ping -n 6 localhost >nul 2>&1

or on Windows 7 or later use timeout:

timeout 6 >nul

Questions:
Answers:

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.

Questions:
Answers:

Just put this in your batch file where you want the wait.

@ping 127.0.0.1 -n 11 -w 1000 > null

Questions:
Answers:

In Notepad, write:

@echo off
set /a WAITTIME=%1+1
PING 127.0.0.1 -n %WAITTIME% > nul
goto:eof

Now save as wait.bat in the folder C:\WINDOWS\System32,
then whenever you want to wait, use:

CALL WAIT.bat <whole number of seconds without quotes>

Questions:
Answers:

Just use

timeout /t

For example, I mostly use it as

timeout /t 2 /nobreak >NUL

Which means the script will wait 2 seconds before continuing.
By default, a keystroke will put the timeout to 0 instantly, so put ‘/nobreak’ after it so they can’t stop the timeout. Also, >NUL makes the timeout invisible as it typically says how many seconds to go.

Questions:
Answers:

If you’ve got PowerShell on your system, you can just execute this command:

powershell -command "Start-Sleep -s 1"

Edit: from my answer on a similar thread, people raised an issue where the amount of time powershell takes to start is significant compared to how long you’re trying to wait for. If the accuracy of the wait time is important (ie a second or two extra delay is not acceptable), you can use this approach:

powershell -command "$sleepUntil = [DateTime]::Parse('%date% %time%').AddSeconds(5); $sleepDuration = $sleepUntil.Subtract((get-date)).TotalMilliseconds; start-sleep -m $sleepDuration"

This takes the time when the windows command was issued, and the powershell script sleeps until 5 seconds after that time. So as long as powershell takes less time to start than your sleep duration, this approach will work (it’s around 600ms on my machine).

Questions:
Answers:

The Resource Kit has always included this. At least since Windows 2000.

Also, the Cygwin package has a sleep – plop that into your PATH and include the cygwin.dll (or whatever it’s called) and way to go!

Questions:
Answers:

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

Questions:
Answers:

I have been using this C# sleep program. It might be more convenient for you if C# is your preferred language:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace sleep
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 1)
            {
                double time = Double.Parse(args[0]);
                Thread.Sleep((int)(time*1000));
            }
            else
            {
                Console.WriteLine("Usage: sleep <seconds>\nExample: sleep 10");
            }
        }
    }
}

Questions:
Answers:

There is a better way to sleep using ping. You’ll want to ping an address that does not exist, so you can specify a timeout with millisecond precision. Luckily, such an address is defined in a standard (RFC 3330), and it is 192.0.2.x. This is not made-up, it really is an address with the sole purpose of not-existing (it may not be clear, but it applies even in local networks):

192.0.2.0/24 – This block is assigned as “TEST-NET” for use in
documentation and example code. It is often used in conjunction with
domain names example.com or example.net in vendor and protocol
documentation. Addresses within this block should not appear on the
public Internet.

To sleep for 123 milliseconds, use ping 192.0.2.1 -n 1 -w 123 >nul

Questions:
Answers:

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.

Questions:
Answers:

Even more lightweight than the Python solution is a Perl
one-liner.

To sleep for seven seconds put this in the BAT script:

perl -e "sleep 7"

This solution only provides a resolution of one second.

If you need higher resolution then use the Time::HiRes
module from CPAN. It provides usleep() which sleeps in
microseconds and nanosleep() which sleeps in nanoseconds
(both functions takes only integer arguments). See the
Stack Overflow question How do I sleep for a millisecond in Perl? for further details.

I have used ActivePerl for many years. It is very easy to
install.

Questions:
Answers:

The best solution that should work on all Windows versions after Windows 2000 would be:

timeout numbersofseconds /nobreak > nul

Questions:
Answers:

Or command line Python, for example, for 6 and a half seconds:

python -c "import time;time.sleep(6.5)"

Questions:
Answers:

The pathping.exe can sleep less than second.

@echo off
setlocal EnableDelayedExpansion 
echo !TIME! & pathping localhost -n -q 1 -p %~1 2>&1 > nul & echo !TIME!

.

> sleep 10
17:01:33,57
17:01:33,60

> sleep 20
17:03:56,54
17:03:56,58

> sleep 50
17:04:30,80
17:04:30,87

> sleep 100
17:07:06,12
17:07:06,25

> sleep 200
17:07:08,42
17:07:08,64

> sleep 500
17:07:11,05
17:07:11,57

> sleep 800
17:07:18,98
17:07:19,81

> sleep 1000
17:07:22,61
17:07:23,62

> sleep 1500
17:07:27,55
17:07:29,06

Questions:
Answers:

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).

Questions:
Answers:

From Windows Vista on you have the TIMEOUT and SLEEP commands, but to use them on Windows XP or Windows Server 2003, you’ll need the Windows Server 2003 resource tool kit.

Here you have a good overview of sleep alternatives (the ping approach is the most popular as it will work on every Windows machine), but there’s (at least) one not mentioned which (ab)uses the W32TM (Time Service) command:

w32tm /stripchart /computer:localhost /period:1 /dataonly /samples:N  >nul 2>&1

Where you should replace the N with the seconds you want to pause. Also, it will work on every Windows system without prerequisites.

Typeperf can also be used:

typeperf "\System\Processor Queue Length" -si N -sc 1 >nul

Questions:
Answers:

You can also use a .vbs file to do specific timeouts:

The code below creates the .vbs file. Put this near the top of you rbatch code:

echo WScript.sleep WScript.Arguments(0) >"%cd%\sleeper.vbs"

The code below then opens the .vbs and specifies how long to wait for:

start /WAIT "" "%cd%\sleeper.vbs" "1000"

In the above code, the “1000” is the value of time delay to be sent to the .vbs file in milliseconds, for example, 1000 ms = 1 s. You can alter this part to be however long you want.

The code below deletes the .vbs file after you are done with it. Put this at the end of your batch file:

del /f /q "%cd%\sleeper.vbs"

And here is the code all together so it’s easy to copy:

echo WScript.sleep WScript.Arguments(0) >"%cd%\sleeper.vbs"
start /WAIT "" "%cd%\sleeper.vbs" "1000"
del /f /q "%cd%\sleeper.vbs"

Questions:
Answers:

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

Questions:
Answers:

This was tested on Windows XP SP3 and Windows 7 and uses CScript. I put in some safe guards to avoid del “” prompting. (/q would be dangerous)

Wait one second:

sleepOrDelayExecution 1000

Wait 500 ms and then run stuff after:

sleepOrDelayExecution 500 dir \ /s

sleepOrDelayExecution.bat:

@echo off
if "%1" == "" goto end
if NOT %1 GTR 0 goto end
setlocal
set sleepfn="%temp%\sleep%random%.vbs"
echo WScript.Sleep(%1) >%sleepfn%
if NOT %sleepfn% == "" if NOT EXIST %sleepfn% goto end
cscript %sleepfn% >nul
if NOT %sleepfn% == "" if EXIST %sleepfn% del %sleepfn%
for /f "usebackq tokens=1*" %%i in (`echo %*`) DO @ set params=%%j
%params%
:end

Questions:
Answers:
ping -n X 127.0.0.1 > nul

Replace X with the number of seconds + 1.

For example, if you were to wait 10 seconds, replace X with 11. To wait 5 seconds, use 6.

Read earlier answers for milliseconds.