关于python:在批处理文件中休眠

Sleeping in a batch file

当编写批处理文件以在Windows机器上自动执行某些操作时,我需要暂停执行几秒钟(通常在测试/等待循环中,等待进程启动)。 当时,我能找到的最佳解决方案是使用ping(我不是你的孩子)来达到预期的效果。 我在这里找到了一个更好的写法,它描述了一个可调用的"wait.bat",实现如下:

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

然后,您可以在自己的批处理文件中包含对wait.bat的调用,并传入要休眠的秒数。

显然,Windows 2003资源工具包提供类似Unix的睡眠命令(最后!)。 与此同时,对于我们这些仍然使用WindowsXP,Windows 2000或(可悲)Windows NT的人来说,还有更好的方法吗?

我在接受的答案中修改了sleep.py脚本,因此如果在命令行上没有传递参数,则默认为1秒:

1
2
3
import time, sys

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


从WindowsVista开始可以使用timeout命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

注意:它不适用于输入重定向 - 一些简单的例子:

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


使用所概述的ping方法是当我不能(或不想)添加更多可执行文件或安装任何其他软件时如何执行此操作。

你应该ping那些不存在的东西,然后使用-w标志使它在那段时间后失败,而不是ping那里的东西(比如localhost)-n次。这使您可以处理不到一秒的时间,我认为它稍微准确一些。

例如

(不测试1.1.1.1)

1
2
3
4
5
ECHO Waiting 15 seconds

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


SLEEP.exe包含在大多数资源工具包中,例如Windows Server 2003资源工具包也可以安装在Windows XP上。

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

我不同意我在这里找到的答案。

我完全基于WindowsXP功能使用以下方法在批处理文件中执行延迟:

DELAY.BAT:

1
2
3
4
5
6
7
8
9
10
@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

您也可以在计算中插入日期,以便在延迟时间间隔超过午夜时该方法也可以使用。


我遇到了类似的问题,但我只是敲了一个很短的C ++控制台应用程序来做同样的事情。只需运行MySleep.exe 1000 - 可能比下载/安装整个资源工具包更容易。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <tchar.h>
#include <stdio.h>
#include"Windows.h"

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

如果您安装了Python,或者不介意安装它(它还有其他用途:),只需创建以下sleep.py脚本并将其添加到PATH中的某个位置:

1
2
3
import time, sys

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

如果您有此需要,它将允许亚秒级暂停(例如,1.5秒,0.1等)。如果要将其称为sleep而不是sleep.py,则可以将.PY扩展名添加到PATHEXT环境变量中。在WindowsXP上,您可以在以下位置编辑它:

我的电脑→属性(菜单)→高级(标签)→环境变量(按钮)→系统变量(框架)

更新:从Windows Vista及以后版本提供的timeout命令应该是使用的命令,如此静默的另一个答案中所述。


在服务器故障时,问了一个类似的问题,那里的解决方案是:

1
choice /d y /t 5 > nul


您可以使用Windows cscript WSH层和此wait.js JavaScript文件:

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


根据您的兼容性需求,使用ping

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

例如等待5秒钟,使用

1
ping -n 6 localhost >nul 2>&1

或者在Windows 7或更高版本上使用timeout

1
timeout 6 >nul


你可以使用ping:

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

它将等待10秒。

你必须使用11的原因是因为第一次ping立即熄灭,而不是一秒钟之后。该数字应始终比您要等待的秒数多一个。

请记住,-w的目的不是等待一秒钟。这是为了确保在出现网络问题时等待不超过一秒钟。 ping本身每秒会发送一个ICMP数据包。 localhost可能不需要它,但旧的习惯很难。


使用ping有一种更好的睡眠方式。您需要ping不存在的地址,因此您可以指定毫秒精度的超时。幸运的是,这样的地址是在标准(RFC 3330)中定义的,它是192.0.2.x。这不是弥补,它实际上是一个地址,其唯一目的是不存在(可能不太清楚,但它甚至适用于本地网络):

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.

要睡眠123毫秒,请使用ping 192.0.2.1 -n 1 -w 123 >nul


1
timeout /t <seconds> <options>

例如,要使脚本执行非不间断的2秒等待:

1
timeout /t 2 /nobreak >NUL

这意味着脚本将在继续之前等待2秒。

默认情况下,按键会中断超时,因此如果您不希望用户能够中断(取消)等待,请使用/nobreak开关。此外,超时将提供每秒通知以通知用户需要等待多长时间;这可以通过将命令传递给NUL来删除。

编辑:正如@martineau在评论中指出的那样,timeout命令仅适用于Windows 7及更高版本。此外,ping命令使用的处理器时间少于timeout。我仍然相信在可能的情况下使用timeout,因为它比ping'hack'更具可读性。在这里阅读更多。


如果您的系统上有PowerShell,则可以执行以下命令:

1
powershell -command"Start-Sleep -s 1"

编辑:从我在类似线程上的回答中,人们提出了一个问题,即PowerShell启动所需的时间与您尝试等待的时间相比是显着的。如果等待时间的准确性很重要(即不能接受额外的两秒或两个延迟),您可以使用以下方法:

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

这将花费发出Windows命令的时间,并且powershell脚本会在该时间之后休眠5秒。因此,只要powershell启动的时间少于睡眠持续时间,这种方法就可以工作(我的机器上的时间大约为600毫秒)。


只需将它放在您想要等待的批处理文件中。

1
@ping 127.0.0.1 -n 11 -w 1000 > null


Resource Kit始终包含此功能。至少从Windows 2000开始。

此外,Cygwin包中有一个sleep - plop进入你的PATH并包含cygwin.dll(或其他任何名称)和方法!


在记事本中,写:

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

现在保存为文件夹C: WINDOWS System32中的wait.bat,
那么每当你想等待时,使用:

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


我喜欢Aacini的回应。我添加它来处理这一天,并使其能够处理厘秒(%TIME%输出H:MM:SS.CC):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
: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

我一直在使用这个C#睡眠程序。如果C#是您的首选语言,对您来说可能更方便:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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>
Example: sleep 10"
);
            }
        }
    }
}

或者命令行Python,例如,持续6秒半:

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


Perl比Python解决方案更轻量级
需要一行代码。

要睡7秒钟,请将其放入BAT脚本中:

1
perl -e"sleep 7"

该解决方案仅提供一秒的分辨率。

如果您需要更高的分辨率,请使用Time :: HiRes
来自CPAN的模块。它提供usleep()睡觉
微秒和nanosleep(),以纳秒为单位休眠
(两个函数只接受整数参数)。见
StackOverflow问题如何在Perl中睡眠一毫秒?了解更多详情。

我已经使用ActivePerl多年了。这很容易
安装。


ping的用法很好,只要你只是想"等一下"。这是因为您依赖于下面的其他功能,例如您的网络工作以及127.0.0.1上没有任何回答的事实。 ;-)也许它不太可能失败,但这并非不可能......

如果要确保等待指定的时间,则应使用sleep功能(其优点还在于它不使用CPU电源或等待网络准备就绪)。

要找到已经制作的睡眠可执行文件是最方便的方法。只需将其放入Windows文件夹或标准路径的任何其他部分即可,它始终可用。

否则,如果您有编译环境,您可以轻松自己制作一个。
sleep功能在kernel32.dll中可用,因此您只需使用该功能即可。 :-)
对于VB / VBA,在源代码的开头声明以下内容以声明sleep函数:

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

对于C#:

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

您可以在此处找到有关Sleep功能(MSDN)中此功能(自Windows 2000以来可用)的更多信息。

在标准C中,sleep()包含在标准库中,而在Microsoft的Visual Studio C中,如果内存为我提供,则该函数名为sleep()。 ;-)这两个参数以秒为单位,而不是以毫秒为前两个声明。


在Windows 2000之后适用于所有Windows版本的最佳解决方案是:

1
timeout numbersofseconds /nobreak > nul


我对此印象深刻:

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

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

从技术上讲,你告诉choice命令只接受y。它默认为y,在5秒内完成,不绘制提示,并转储它对NUL说的任何内容(如Linux上的null终端)。


从WindowsVista开始,您有TIMEOUT和SLEEP命令,但要在WindowsXP或Windows Server 2003上使用它们,您将需要Windows Server 2003资源工具包。

在这里你可以很好地了解睡眠替代方案(ping方法最受欢迎,因为它可以在每台Windows机器上运行),但是(至少)没有提到哪一个(ab)使用W32TM(时间服务)命令:

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

你应该用你想要暂停的秒数替换N.此外,它将适用于没有先决条件的每个Windows系统。

也可以使用Typeperf:

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


您还可以使用.vbs文件执行特定的超时:

下面的代码创建.vbs文件。把它放在你的rbatch代码的顶部附近:

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

然后,下面的代码打开.vbs并指定等待的时间:

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

在上面的代码中,"1000"是以毫秒为单位发送到.vbs文件的时间延迟值,例如1000ms = 1s。您可以将此部分更改为您想要的任何时间。

完成后,下面的代码将删除.vbs文件。把它放在批处理文件的末尾:

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

这里是代码,所以很容易复制:

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

pathping.exe可以睡不到秒。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
> 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

由于其他人正在建议第三方程序(Python,Perl,自定义应用程序等),另一个选项是Windows的GNU CoreUtils,可从http://gnuwin32.sourceforge.net/packages/coreutils.htm获得。

2个部署选项:

  • 安装完整包(包括完整的CoreUtils套件,依赖项,文档等)。
  • 仅安装'sleep.exe'二进制文件和必要的依赖项(使用depends.exe来获取依赖项)。
  • 部署CoreUtils的一个好处是,您还将获得许多其他有助于编写脚本的程序(Windows批处理有很多不足之处)。


    您可以通过在标题栏中放置PAUSE消息来获得幻想:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @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

    这是在WindowsXP SP3和Windows7上测试的,并使用CScript。我放了一些安全防护装置以避免del"提示。(/q会很危险)

    等一下:

    sleepOrDelayExecution 1000

    等待500毫秒然后运行之后:

    1
    sleepOrDelayExecution 500 dir \ /s

    sleepOrDelayExecution.bat:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @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

    1
    ping -n X 127.0.0.1 > nul

    将X替换为秒数+ 1。

    例如,如果您要等待10秒钟,请将X替换为11.要等待5秒钟,请使用6。

    阅读前面的答案毫秒。