在批处理文件中休眠

165

当编写Windows批处理文件以自动化某些操作时,我需要暂停其执行几秒钟(通常在测试/等待循环中,等待进程启动)。当时,我能找到的最佳解决方案使用ping(我不是在开玩笑)来实现所需的效果。我发现了一个更好的写作方法here,其中描述了一个可调用的“wait.bat”,实现如下:

@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的sleep命令(终于有了!)。与此同时,对于那些仍在使用Windows XP、Windows 2000或(遗憾地)Windows NT的人来说,是否有更好的方法呢?

我修改了sleep.py脚本中被接受的答案,以便如果没有在命令行上传递任何参数,则默认为一秒钟:

import time, sys

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

微软的下载页面显示Windows 2003资源工具包也适用于XP。 恐怕没有其他选择,只能使用“外部”实用程序来进行等待:XP命令处理器中没有类似的功能。 - GerG
请查看以下两个链接,了解如何在批处理文件中实现等待命令和睡眠命令: - Wael Dalloul
2
你有几个选项 - 使用 ping 命令模拟睡眠,或下载包含 sleep 命令的 Windows 资源工具包。更多详情请参见:批处理文件 SLEEP 命令 - Rudu
http://stackoverflow.com/questions/5437201/how-to-wait-in-a-batch-script/5822491 http://stackoverflow.com/questions/1304738/wait-in-console https://dev59.com/OG445IYBdhLWcg3wWI-L https://dev59.com/23VC5IYBdhLWcg3w2k-I - Chris Moschini
批处理文件停止各种技术的良好总结:https://www.robvanderwoude.com/wait.php - user1934286
显示剩余5条评论
34个回答

8
timeout /t <seconds> <options>

例如,为了使脚本执行不可中断的2秒等待:
timeout /t 2 /nobreak >NUL

这意味着脚本将在继续之前等待2秒钟。 默认情况下,按键将打断超时,所以如果你不想让用户能够中断(取消)等待,请使用/nobreak开关。此外,超时将提供每秒通知,通知用户还有多长时间可以等待;这可以通过将命令导向NUL来删除。编辑:如评论中@martineau指出的那样,timeout命令仅适用于Windows 7及以上版本。此外,ping命令比timeout命令使用更少的处理器时间。然而,我仍然相信在可能的情况下使用timeout,因为它比ping“hack”更易读。在此处阅读更多信息here

2
显然,此命令仅适用于Windows 7/2008和XP资源套件(可能也适用于8/8.1)。该来源还声称“ping”方法使用的处理器时间较少。 - martineau

8
使用ping有更好的睡眠方法。您需要ping一个不存在的地址,这样您就可以指定毫秒精度的超时时间。幸运的是,这样的地址在标准中已经定义了(RFC 3330),它就是192.0.2.x。这不是虚构的,它确实是一个唯一的不存在的地址。需要明确的是,即使在本地网络中也适用。

192.0.2.0/24 - 此块被分配为“TEST-NET”,供文档和示例代码使用。通常与域名example.com或example.net一起在供应商和协议文档中使用。此块内的地址不应出现在公共互联网上。

要睡眠123毫秒,请使用ping 192.0.2.1 -n 1 -w 123 >nul 更新:根据评论,还有127.255.255.255

是的,这比将“1”添加到“-n”参数更容易编写和理解。 - Peter Mortensen
然而,我已经进行了测量(使用100个ping)。如果我使用-n 3 -w 124,则实际时间正好为(3 + 1)*(124 + 1)= 4 * 125 = 500毫秒。定时非常稳定,在读数中精确到10毫秒的分辨率(通过带有时间的CMD提示符)-底层分辨率绝对优于10毫秒(不受通常的16毫秒滴答分辨率的影响)。 - Peter Mortensen
@mafu说192.0.2.0/24不应该被使用并不意味着它不能被使用,因此不能真正保证没有回复echo请求。例如,为任何Windows PC配置静态IPv4地址192.0.2.1和子网掩码255.255.255.0,并将网络适配器连接到任何其他设备上。一个简单的交换机就足够了,上面没有连接其他设备。然后在这台Windows PC上运行“ping 192.0.2.1”,可以看到Windows TCP/IP堆栈会回复echo请求。有多少人知道192.0.2.0/24不应该用于静态IPv4地址? - Mofi
2
根据这里评论中的讨论,似乎192.0.2.1并不是完全可靠的选择,有人建议使用127.255.255.255。你有什么想法? - JLRishe
上面帖子中提到的评论现已被删除(可能是因为NLN),但我同意将IP地址更改为127.255.255.255,因为它是Windows中的广播回送地址,已经默认分配给它(您可以通过在cmd中运行“route print”并查看它打印的IPv4路由表来确认这一点)。 - Hoppeduppeanut

7
如果您的系统上安装了PowerShell,您只需执行此命令即可:
powershell -command "Start-Sleep -s 1"

编辑:从我在一个类似的帖子上的回答,人们提出了一个问题,即powershell启动所需的时间与您等待的时间相比显着。如果等待时间的准确性很重要(即多等一两秒钟是不可接受的),则可以使用以下方法:

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

这个命令记录了Windows命令被执行的时间,然后PowerShell脚本会休眠直到该时间之后的5秒。只要PowerShell启动所需的时间少于休眠持续时间,此方法就可以正常工作(在我的机器上大约为600毫秒)。

如果你在powershell中添加参数“-noprofile”,无论你向用户配置文件中添加了多少额外内容,你的powershell都会启动得相当快。 - Carl Walsh

5

只需在批处理文件中放置此代码,即可实现等待功能。

@ping 127.0.0.1 -n 11 -w 1000 > null

这与paxdiablo的答案有何不同? - Peter Mortensen
2
这并没有什么不同,但是这里的答案来自于多个合并的问题,所以当我回复时,并不是所有的答案都存在。 - Brent Stewart

4
在记事本中写入以下内容:
@echo off
set /a WAITTIME=%1+1
PING 127.0.0.1 -n %WAITTIME% > nul
goto:eof

现在将其保存为wait.bat,保存在C:\WINDOWS\System32文件夹中, 然后每当你想要等待时,使用以下命令:
CALL WAIT.bat <whole number of seconds without quotes>

它会重复地对自身进行ping操作,每次ping之间等待一秒钟,然后返回给调用程序。我没有看到无限循环,但我已经亲自测试过了。 - SuperKael
我的错误,没有无限循环。但是,如在其他答案中提到的那样,最好不仅仅ping一次某个东西,并使用“-w Timeout”选项来设置延迟时间(以毫秒为单位),而不是“-n Count”整数重试次数选项。 - martineau
“-w超时”可能更好,但是我确保它会比输入的时间多ping一次。 - SuperKael

4

资源工具包一直都包含了这个功能,至少从Windows 2000开始。

此外,Cygwin软件包中有一个sleep命令 - 将其加入你的PATH并包含cygwin.dll(或者它被称为其他什么),就可以使用了!


2
请注意,cygwin1.dll与其不同版本并不能和平共处。你最好在你的计算机上只有一个cygwin1.dll,否则你会遇到奇怪的故障。 - JesperE
哪个资源包?似乎有不止一个。你能更新一下你的回答吗? - Peter Mortensen

3

我喜欢Aacini的回答。我对它进行了修改,以处理日期并使其能够处理百分之一秒%TIME%输出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

我一直在使用这个C#睡眠程序。如果C#是您偏好的语言,它可能更加方便:

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");
            }
        }
    }
}

3
使用ping命令是不错的,只要你想“等一下”。这是因为它依赖于其他功能,例如网络工作和127.0.0.1上没有任何响应。也许它失败的可能性不大,但并非不可能...
如果您想确保等待指定的时间,您应该使用sleep功能(它还具有不使用CPU功率或等待网络准备好的优点)。
查找已经制作好的可执行文件以进行睡眠是最方便的方法。只需将其放入Windows文件夹或任何其他标准路径的部分即可随时使用。
否则,如果您有编译环境,可以轻松地自己制作一个。Sleep函数在kernel32.dll中可用,所以您只需要使用那个。:-) 对于VB / VBA,请在源代码开头声明以下内容以声明睡眠函数:
private Declare Sub Sleep Lib "kernel32" Alias "Sleep" (byval dwMilliseconds as Long)

针对C#:

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

你可以在 Sleep function (MSDN) 中了解更多有关此功能的信息(自 Windows 2000以来可用)。

在标准C中,sleep() 已包含在标准库中,并且在 Microsoft 的 Visual Studio C中,如果我没记错的话,该函数的名称为 Sleep()。这两个函数都接受以秒为单位的参数,而不是毫秒。


1
在 .net 框架中可以使用 Sleep 方法 - 可以查看线程类,例如:using System.Threading; .... Thread.Sleep(1000); - John Sibly
2
如果“ping 127.0.0.1”失败了,那么你需要担心的比“睡眠”更严重——这是回环接口,任何RPC都可能出现问题。 - Piskvor left the building

3
比Python解决方案更加轻量级的是一个Perl单行命令。
要让脚本休眠七秒,将以下内容放入BAT脚本中:
perl -e "sleep 7"

这个解决方案只提供了一秒的分辨率。

如果您需要更高的分辨率,请使用来自CPAN的Time::HiRes模块。它提供了usleep(),可以以微秒为单位休眠,以及nanosleep(),可以以纳秒为单位休眠(这两个函数仅接受整数参数)。有关详细信息,请参见Stack Overflow问题“如何在Perl中休眠一毫秒?”

我已经使用ActivePerl很多年了。它非常容易安装。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接