Durmiendo en un archivo por lotes

Al escribir un archivo por lotes para automatizar algo en un cuadro de Windows, he necesitado pausar su ejecución durante varios segundos (generalmente en un ciclo de prueba / espera, esperando a que se inicie un proceso). En ese momento, la mejor solución que pude encontrar utiliza ping (no bromeo) para lograr el efecto deseado. He encontrado un mejor resumen del mismo aquí , que describe un “wait.bat” llamable, implementado de la siguiente manera:

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

Luego puede incluir llamadas a wait.bat en su propio archivo por lotes, pasando el número de segundos para dormir.

Aparentemente, el Kit de recursos de Windows 2003 proporciona un comando de suspensión similar a Unix (¡por fin!). Mientras tanto, para aquellos de nosotros que todavía usamos Windows XP, Windows 2000 o (lamentablemente) Windows NT , ¿hay alguna manera mejor?

sleep.py la sleep.py comandos sleep.py en la respuesta aceptada , de modo que el valor predeterminado sea de un segundo si no se pasan argumentos en la línea de comandos:

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

Si tiene Python instalado, o no le importa instalarlo (también tiene otros usos :), simplemente cree el siguiente script sleep.py y agréguelo en algún lugar de su PATH:

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

Permitirá pausas de menos de un segundo (por ejemplo, 1.5 segundos, 0.1, etc.), en caso de que lo necesite. Si desea llamarlo como sleep lugar de sleep.py , entonces puede agregar la extensión .PY a su variable de entorno PATHEXT. En Windows XP, puedes editarlo en:

Mi PC → Propiedades (menú) → Avanzadas (pestaña) → Variables de entorno (botón) → Variables del sistema (marco)

El comando de timeout está disponible desde Windows Vista en adelante:

 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 

Nota: No funciona con la redirección de entrada – ejemplo trivial:

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

Usar el método de ping como se describe es cómo lo hago cuando no puedo (o no quiero) agregar más ejecutables o instalar cualquier otro software.

Debería hacer ping a algo que no está allí y usar el indicador -w para que falle después de ese tiempo, no hacer ping a algo que esté allí (como localhost) -n veces. Esto le permite manejar el tiempo en menos de un segundo, y creo que es un poco más preciso.

p.ej

(prueba que 1.1.1.1 no se toma)

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

No estoy de acuerdo con las respuestas que encontré aquí.

Utilizo el siguiente método completamente basado en las capacidades de Windows XP para hacer un retraso en un archivo por lotes:

DELAY.BAT:

 @ECHO OFF REM DELAY seconds REM GET ENDING SECOND FOR /F "TOKENS=1-3 DELIMS=:." %%A IN ("%TIME%") DO SET /AH=%%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 /AH=%%A, M=1%%B%%100, S=1%%C%%100, CURRENT=(H*60+M)*60+S IF %CURRENT% LSS %ENDING% GOTO WAIT 

También puede insertar el día en el cálculo para que el método también funcione cuando el intervalo de demora pasa la medianoche.

SLEEP.exe está incluido en la mayoría de los Kits de recursos, por ejemplo, el Kit de recursos de Windows Server 2003, que también se puede instalar en Windows XP.

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

Me enfrenté a un problema similar, pero acabo de encontrar una aplicación de consola C ++ muy corta para hacer lo mismo. Simplemente ejecute MySleep.exe 1000 : quizás sea más fácil que descargar / instalar todo el kit de recursos.

 #include  #include  #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; } 

Sobre la falla del servidor, se hizo una pregunta similar , la solución fue:

 choice /dy /t 5 > nul 

Podría usar la capa WSH cscript de Windows y este archivo de JavaScript wait.js :

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

Dependiendo de sus necesidades de compatibilidad, use ping :

 ping -n  localhost >nul 2>&1 

por ejemplo, para esperar 5 segundos, use

 ping -n 6 localhost >nul 2>&1 

o en Windows 7 o posterior usa el timeout :

 timeout 6 >nul 

Puedes usar ping:

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

Se esperará 10 segundos.

La razón por la que tiene que usar 11 es porque el primer ping se apaga de inmediato, no después de un segundo. El número siempre debe ser uno más que el número de segundos que desea esperar.

Tenga en cuenta que el propósito de -w no es esperar un segundo. Es para asegurarse de que no espere más de un segundo en caso de que haya problemas de red. ping por sí solo enviará un paquete ICMP por segundo. Probablemente no sea necesario para el localhost, pero los viejos hábitos mueren.

 timeout /t   

Por ejemplo, para hacer que el script realice una espera de 2 segundos ininterrumpible:

 timeout /t 2 /nobreak >NUL 

Lo que significa que el script esperará 2 segundos antes de continuar.

De manera predeterminada, una pulsación de tecla interrumpirá el tiempo de espera, así que use el interruptor /nobreak si no desea que el usuario pueda interrumpir (cancelar) la espera. Además, el tiempo de espera proporcionará notificaciones por segundo para notificar al usuario cuánto tiempo queda para esperar; Esto se puede eliminar canalizando el comando a NUL .

Editar: como @martineau señala en los comentarios , el comando de timeout solo está disponible en Windows 7 y superior. Además, el comando ping utiliza menos tiempo de procesador que el tiempo de timeout . Sin embargo, sigo creyendo en usar el timeout cuando sea posible, ya que es más legible que el ping ‘hack’. Lea más aquí .

Simplemente ponga esto en su archivo por lotes donde desee la espera.

 @ping 127.0.0.1 -n 11 -w 1000 > null 

Hay una mejor manera de dormir usando ping. Querrá hacer ping a una dirección que no existe, por lo que puede especificar un tiempo de espera con una precisión de milisegundos. Afortunadamente, dicha dirección se define en un estándar (RFC 3330), y es 192.0.2.x Esto no está hecho, realmente es una dirección con el único propósito de no existir (puede que no esté claro, pero se aplica incluso en redes locales):

192.0.2.0/24 – Este bloque se asigna como “TEST-NET” para su uso en la documentación y el código de ejemplo. A menudo se usa junto con los nombres de dominio example.com o example.net en la documentación del proveedor y del protocolo. Las direcciones dentro de este bloque no deben aparecer en la Internet pública.

Para dormir durante 123 milisegundos, use ping 192.0.2.1 -n 1 -w 123 >nul

En el Bloc de notas, escriba:

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

Ahora guarde como wait.bat en la carpeta C: \ WINDOWS \ System32, luego, cuando quiera esperar, use:

 CALL WAIT.bat  

Si tienes PowerShell en tu sistema, puedes ejecutar este comando:

 powershell -command "Start-Sleep -s 1" 

Edición: de mi respuesta en un hilo similar , las personas plantearon un problema en el que la cantidad de tiempo que PowerHell tarda en comenzar es importante en comparación con el tiempo que está intentando esperar. Si la precisión del tiempo de espera es importante (es decir, un segundo o dos retrasos adicionales no es aceptable), puede utilizar este método:

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

Esto toma el tiempo cuando se emitió el comando de Windows, y la secuencia de comandos powershell duerme hasta 5 segundos después de ese tiempo. Por lo tanto, mientras powershell tarde menos tiempo en comenzar que la duración de su sueño, este enfoque funcionará (es de unos 600 ms en mi máquina).

El kit de recursos siempre ha incluido esto. Al menos desde Windows 2000.

Además, el paquete Cygwin tiene una sleep que se incluye en tu RUTA e incluye el cygwin.dll (o como se llame) y ¡el camino a seguir!

Me gusta la respuesta de Aacini . Lo agregué para manejar el día y también habilitarlo para manejar los centisegundos ( %TIME% salida 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 /AH=%%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 /AH=%%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 

He estado usando este progtwig de sueño C #. Podría ser más conveniente para usted si C # es su idioma preferido:

 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 \nExample: sleep 10"); } } } } 

O la línea de comandos de Python, por ejemplo, durante 6 segundos y medio:

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

El uso del ping es bueno, siempre y cuando solo quieras “esperar un poco”. Esto, ya que depende de otras funciones que se encuentran debajo, como que su red funcione y el hecho de que no hay nada que responda en 127.0.0.1. 😉 Tal vez no es muy probable que falle, pero no es imposible …

Si desea asegurarse de que está esperando exactamente el tiempo especificado, debe usar la función de sleep (que también tiene la ventaja de que no usa la potencia de la CPU o esperar a que la red esté lista).

Encontrar un ejecutable ya hecho para dormir es la forma más conveniente. Simplemente colóquelo en su carpeta de Windows o en cualquier otra parte de su ruta estándar y siempre estará disponible.

De lo contrario, si tiene un entorno de comstackción, puede crearlo usted mismo fácilmente. La función Sleep está disponible en kernel32.dll , así que solo necesitas usar esa. 🙂 Para VB / VBA, declare lo siguiente al principio de su fuente para declarar una función de suspensión:

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

Para C #:

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

Aquí encontrará más información sobre esta funcionalidad (disponible desde Windows 2000) en la función Suspender (MSDN).

En la norma C, sleep() está incluido en la biblioteca estándar y en Visual Studio C de Microsoft, la función se llama Sleep() , si la memoria me sirve. 😉 Esos dos toman el argumento en segundos, no en milisegundos como las dos declaraciones anteriores.

Incluso más ligero que la solución de Python es una línea de Perl.

Para dormir durante siete segundos ponga esto en el script BAT:

 perl -e "sleep 7" 

Esta solución solo proporciona una resolución de un segundo.

Si necesita una resolución más alta, use el módulo Time :: HiRes de CPAN. Proporciona usleep() que duerme en microsegundos y nanosleep() que duerme en nanosegundos (ambas funciones solo toman argumentos enteros). Ver la pregunta de desbordamiento de stack ¿ Cómo duermo durante un milisegundo en Perl? para mas detalles.

He usado ActivePerl durante muchos años. Es muy fácil de instalar.

La mejor solución que debería funcionar en todas las versiones de Windows después de Windows 2000 sería:

 timeout numbersofseconds /nobreak > nul 

El pathping.exe puede dormir menos de un segundo.

 @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 

Estoy impresionado con este:

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

 choice /n /cy /dy /t 5 > NUL 

Técnicamente, le está diciendo al comando de choice que acepte solo y. El valor predeterminado es y, hacerlo en 5 segundos, no generar ningún mensaje y volcar todo lo que diga a NUL (como terminal nulo en Linux).

Desde Windows Vista, tiene los comandos TIMEOUT y SLEEP , pero para usarlos en Windows XP o Windows Server 2003, necesitará el kit de herramientas de recursos de Windows Server 2003 .

Aquí tiene una buena descripción general de las alternativas de suspensión (el enfoque de ping es el más popular, ya que funcionará en todas las máquinas con Windows), pero hay (al menos) una no mencionada que (ab) usa el W32TM (Servicio de hora):

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

Donde deberías reemplazar la N con los segundos que deseas pausar. Además, funcionará en todos los sistemas de Windows sin requisitos previos.

Typeperf también se puede utilizar:

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

También puede usar un archivo .vbs para hacer tiempos de espera específicos:

El siguiente código crea el archivo .vbs. Pon esto cerca de tu código rbatch:

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

El siguiente código abre los .vbs y especifica cuánto tiempo esperar:

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

En el código anterior, “1000” es el valor del tiempo de retardo que se enviará al archivo .vbs en milisegundos, por ejemplo, 1000 ms = 1 s. Puedes alterar esta parte para que sea lo que quieras.

El siguiente código elimina el archivo .vbs una vez que haya terminado con él. Ponga esto al final de su archivo por lotes:

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

Y aquí está el código completo, así que es fácil de copiar:

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

Puede ser elegante colocando el mensaje de PAUSA en la barra de título:

 @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 

Esto se probó en Windows XP SP3 y Windows 7 y utiliza CScript. Puse algunos guardias seguros para evitar las “” indicaciones. ( /q seria peligroso)

Espera un segundo:

sleepOrDelayExecution 1000

Espera 500 ms y luego ejecuta cosas después de:

 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 

Dado que otros sugieren progtwigs de terceros (Python, Perl, aplicación personalizada, etc.), otra opción es GNU CoreUtils para Windows disponible en http://gnuwin32.sourceforge.net/packages/coreutils.htm .

2 opciones para la implementación:

  1. Instale el paquete completo (que incluirá el paquete completo de CoreUtils, dependencias, documentación, etc.).
  2. Instale solo el binario ‘sleep.exe’ y las dependencias necesarias (use depends.exe para obtener dependencias).

Una de las ventajas de la implementación de CoreUtils es que además obtendrá una gran cantidad de otros progtwigs que son útiles para la creación de secuencias de comandos (el lote de Windows deja mucho que desear).

 ping -n X 127.0.0.1 > nul 

Reemplace X con el número de segundos + 1.

Por ejemplo, si tuviera que esperar 10 segundos, reemplace X por 11. Para esperar 5 segundos, use 6.

Lee las respuestas anteriores por milisegundos.