Windows batch: sleep [duplicate] - windows

This question already has answers here:
Sleeping in a batch file
(34 answers)
Closed 9 years ago.
How do I get a Windows batch script to wait a few seconds?
sleep and wait don't seem to work (unrecognized command).

You can try
ping -n XXX 127.0.0.1 >nul
where XXX is the number of seconds to wait, plus one.

I don't know why those commands are not working for you, but you can also try timeout
timeout <delay in seconds>

timeout /t 10 /nobreak > NUL
/t specifies the time to wait in seconds
/nobreak won't interrupt the timeout if you press a key (except CTRL-C)
> NUL will suppress the output of the command

To wait 10 seconds:
choice /T 10 /C X /D X /N

Microsoft has a sleep function you can call directly.
Usage: sleep time-to-sleep-in-seconds
sleep [-m] time-to-sleep-in-milliseconds
sleep [-c] commited-memory ratio (1%-100%)
You can just say sleep 1 for example to sleep for 1 second in your batch script.
IMO Ping is a bit of a hack for this use case.

For a pure cmd.exe script, you can use this piece of code that returns the current time in hundreths of seconds.
:gettime
set hh=%time:~0,2%
set mm=%time:~3,2%
set ss=%time:~6,2%
set cc=%time:~-2%
set /A %1=hh*360000+mm*6000+ss*100+cc
goto :eof
You may then use it in a wait loop like this.
:wait
call :gettime wait0
:w2
call :gettime wait1
set /A waitt = wait1-wait0
if !waitt! lss %1 goto :w2
goto :eof
And putting all pieces together:
#echo off
setlocal enableextensions enabledelayedexpansion
call :gettime t1
echo %t1%
call :wait %1
call :gettime t2
echo %t2%
set /A tt = (t2-t1)/100
echo %tt%
goto :eof
:wait
call :gettime wait0
:w2
call :gettime wait1
set /A waitt = wait1-wait0
if !waitt! lss %1 goto :w2
goto :eof
:gettime
set hh=%time:~0,2%
set mm=%time:~3,2%
set ss=%time:~6,2%
set cc=%time:~-2%
set /A %1=hh*360000+mm*6000+ss*100+cc
goto :eof
For a more detailed description of the commands used here, check HELP SET and HELP CALL information.

Heh, Windows is uhm... interesting. This works:
choice /T 1 /d y > NUL
choice presents a prompt asking you yes or no. /d y makes it choose yes. /t 1 makes it wait a second before typing it. > NUL squashes output.

The Windows 2003 Resource Kit has a sleep batch file. If you ever move up to PowerShell, you can use:
Start-Sleep -s <time to sleep>
Or something like that.

I rely on JScript. I have a JScript file like this:
// This is sleep.js
WScript.Sleep( WScript.Arguments( 0 ) );
And inside a batch file I run it with CScript (usually it is %SystemRoot%\system32\cscript.exe)
rem This is the calling inside a BAT file to wait for 5 seconds
cscript /nologo sleep.js 5000

I just wrote my own sleep which called the Win32 Sleep API function.

RJLsoftware has a small utility called DelayExec.exe. With this you can execute a delayed start of any program in batches and Windows registry (most useful in ...Windows/.../Run registry).
Usage example:
delayexec "C:\WINDOWS\system32\notepad.exe" 10
or as a sleep command:
delayexec "nothing" 10

Personally I use a Perl one-liner:
perl -e "sleep 10;"
for a 10-second wait. Chances are you'll already have Perl installed on a development machine as part of your git installation; if not you will have to install it, for example, from ActiveState or Strawberry, but it's one of those things I install anyway.
Alternatively, you can install a sleep command from GnuWin32.

Related

Execute multiple batch files concurrently and monitor if their process is completed

I have a main batch file which calls multiple batch files. I want to be able to execute all these batch files at the same time. Once they are all done, I have further processes that needs to carry on in the main batch file.
When I use 'Start' to call the multiple batch files, I'm able to kick off all batch files concurrently but I lose tracking of them. (Main batch file thinks their processes are done the moment it executes other batch files).
When I use 'Call', I'm able to monitor the batch file process, but it kicks off the batch files sequentially instead of concurrently.
Is there a way around this? I have limited permissions on this PC and I'm trying to accomplish this using Batch only.
Main Batch file
call first.bat
call second.bat
call third.bat
:: echo only after all batch process done
echo done!
first.bat
timeout /t 10
second.bat
timeout /t 10
third.bat
timeout /t 10
This is the simplest and most efficient way to solve this problem:
(
start first.bat
start second.bat
start third.bat
) | pause
echo done!
In this method the waiting state in the main file is event driven, so it does not consume any CPU time. The pause command would terminate when anyone of the commands in the ( block ) outputs a character, but start commands don't show any output in this cmd.exe. In this way, pause keeps waiting for a char until all processes started by start commands ends. At that point the pipe line associated to the ( block ) is closed, so the pause Stdin is closed and the command is terminated by cmd.exe.
This will generate a temporary file and lock it by creating a redirection to it, starting the batch subprocesses inside this redirection. When all the subprocesses end the redirection is closed and the temporary file is deleted.
While the subprocesses are running, the file is locked, and we can test this trying to rename the file. If we can rename the file, subprocesses have ended, else some of the processes are still running.
#echo off
setlocal enableextensions disabledelayedexpansion
for %%t in ("%temp%\%~nx0.%random%%random%%random%.tmp") do (
echo Starting subprocesses
9> "%%~ft" (
start "" cmd /c subprocess.bat
start "" cmd /c subprocess.bat
start "" cmd /c subprocess.bat
start "" cmd /c subprocess.bat
start "" cmd /c subprocess.bat
)
echo Waiting for subprocesses to end
break | >nul 2>nul (
for /l %%a in (0) do #(ren "%%~ft" "%%~nxt" && exit || ping -n 2 "")
)
echo Done
) & del "%%~ft"
note: any process started inside the subprocesses will also hold the redirection and the lock. If your code leaves something running, this can not be used.
#ECHO Off
SETLOCAL
:: set batchnames to run
SET "batches=first second third"
:: make a tempdir
:maketemp
SET /a tempnum=%random%
SET "tempdir=%temp%\%tempnum%"
IF EXIST "%tempdir%*" (GOTO maketemp) ELSE (MD "%tempdir%")
FOR %%a IN (%batches%) DO START "%%a" %%a "%tempdir%\%%a"
:wait
timeout /t 1 >nul
FOR %%a IN (%batches%) DO IF exist "%tempdir%\%%a" GOTO wait
RD "%tempdir%" /S /Q
GOTO :EOF
Where the batches are constructed like
#ECHO OFF
:: just delay for 5..14 seconds after creating a file "%1", then delete it and exit
SETLOCAL
ECHO.>"%~1"
SET /a timeout=5+(%RANDOM% %% 10)
timeout /t %timeout% >NUL
DEL /F /Q "%~1"
EXIT
That is, each called batch first creates a file in the temporary directory, then deletes it after the required process is run. The filename to create/delete is provided as the first parameter to the batch and "quoted" because the temp directoryname typically contains separators.
The mainline simply creates a temporary directory and invokes the subprocedures, then repeatedly waits 1 second and checks whether the subprocedures' flagfile have all been deleted. Only if they have all been deleted with the procedure continue to delete the temporary directory
Adding to the answer by Aacini. I was also looking for similar task. Objective was to run multiple commands parallel and extract output (stdout & error) of all parallel processes. Then wait for all parallel processes to finish and execute another command. Following is a sample code for BAT file, can be executed in CMD:
(
start "" /B cmd /c ping localhost -n 6 ^>nul
timeout /t 5 /nobreak
start "" /B /D "C:\users\username\Desktop" cmd /c dir ^> dr.txt ^2^>^&^1
start "" /B cmd /c ping localhost -n 11 ^>nul
timeout /t 10 /nobreak
) | pause
Echo waited
timeout /t 12 /nobreak
All the statements inside () are executed first, wait for them to complete, then last two lines are executed. All commands begining with start are executed simultaneously.

Batch File to Loop a VBScript During Certain Times of the Day

I am very new to batch, so please be easy. That being said, I am attempting to write a batch file that every few minutes will execute a VBScript that updates information on our network. Currently I have:
#ECHO OFF
REM Run VBScript
GOTO SKIP01
:LOOP
wscript "C:\Users\Desktop\RenameMove.vbs"
GOTO SKIP01
:
:
:SKIP01
REM 3 Min Delay
PING 1.1.1.1 -n 10 -w 18000 >NUL
IF HOUR:%time:~0,5% <09:44
GOTO SKIP01
IF HOUR:%time:~0,5% >16:00
GOTO SKIP01
IF HOUR:%time:~0,5% >=09:45
GOTO LOOP
Currently the window will open for a minute or two, then it just closes. If I run the above after removing the first GOTO SKIP01, the VBScript executes perfectly. Then there is a delay and the window closes. I imagine that it is everything under :SKIP01 that is causing the problem. The function I am trying to achieve is for the .BAT file to continuously loop a delay between the hours of 16:01 - 09:44. Then run the VBScript every 3 minutes from 09:45 - 16:00. Searching the forums I have yet to find anything to help. As I said, I am very new to Batch.
RE: My last comment below:
#ECHO OFF
setlocal enableextensions disabledelayedexpansion
set delay=180
set "startTime=09:45"
set "endTime=16:00"
:LOOP
set "now=%time: =0%"
:: ECHO It's %now%, waiting %delay% seconds
echo %date% %time% >> log.txt
if "%now%" geq "%startTime%:00,00" (
GOTO LOOP2
)
:LOOP2
set "now=%time: =0%"
:: ECHO It's %now%, waiting %delay% seconds
echo %date% %time% >> log.txt
if "%now%" lss "%endTime%:00,00" (
:: ECHO Start MSAccess
GOTO CALLVBS
)
:WAIT
REM 10 second delay
PING 127.0.0.1 -n %delay% >REM
GOTO LOOP
:CALLVBS
echo Time to Move!
wscript "C:\Users\ljs\Desktop\Stock_Automation_DO_NOT_EDIT\RenameMove.vbs"
GOTO WAIT
I renamed some things so it made more sense to me, but here is a working version. there are variables at the top for the delay (in seconds) and the start and end time for the window. I also modified your ping delay to something more simple, in my opinion.
Remove the echos for production and add the vbscript file to the CALLVBS function.
#ECHO OFF
setlocal enableextensions disabledelayedexpansion
set delay=180
set "startTime=09:45"
set "endTime=16:00"
:LOOP
set "now=%time: =0%"
ECHO It's %now%, waiting %delay% seconds
if "%now%" geq "%startTime%:00,00" (
ECHO It's after %startTime%
if "%now%" lss "%endTime%:00,00" (
ECHO And it's before %endTime%
GOTO CALLVBS
)
)
:WAIT
REM 10 second delay
PING 127.0.0.1 -n %delay% >REM
GOTO LOOP
:CALLVBS
echo It's time!
REM Call VBS here
GOTO WAIT
Here's what's happening, as explained by someone who barely knows what he's talking about:
ABOUT GOTO
First you need to know that batch files process line-by-line from top to bottom, unless it encounters certain statements like if, for or goto, the last of which being the one we are concerned with here. If the interpreter encounters a GOTO command, it will go to the corresponding label and resume processing code line by line until it finds another GOTO or gets to the end of the file.
SIMPLE EXAMPLE
#echo off
GOTO :FRUITS
:COLORS
echo Red
echo Green
GOTO :END
:FRUITS
echo Apple
echo Banana
GOTO :COLORS
:END
echo Done!
This outputs the following:
Apple
Banana
Red
Green
Done!
BREAKDOWN
Set up variables
#ECHO OFF
setlocal enableextensions disabledelayedexpansion
set delay=180
set "startTime=09:45"
set "endTime=16:00"
This sets some settings and creates some variables for use later. The variables should be self explanatory but
I can elaborate if you want.
check the time
01. :LOOP
02. set "now=%time: =0%"
03. ECHO It's %now%, waiting %delay% seconds
04. if "%now%" geq "%startTime%:00,00" (
05. ECHO It's after %startTime%
06. if "%now%" lss "%endTime%:00,00" (
07. ECHO And it's before %endTime%
08. GOTO CALLVBS
09. )
10. )
This is our "loop". :LOOP denotes what is basically a labeled
section of code that we can go back to any time we want. I called it LOOP
because it is the section we are doing over and over. It may have been more
accurate to call it :CHECKTIME or something similar, as that's what it does.
The label means absolutely nothing to the interpreter so calling it "LOOP"
doesn't mean it's going to repeat. This may be the biggest source of confusion.
Here is a
step-by-step of what each line on this block does (not processing
conditions, just line by line):
Get the current time.
Output the current time
Compare the current time to the endTime variable.
Output the result.
Compare the current time to the startTimevariable.
Output the result.
Goto the CALLVBS section of code
Note that I could have put GOTO WAIT at the end of this block and that might make more sense, but since :WAIT is the next block of
code that's what will process next anyway, so the GOTO would be
superfluous! This may be a second point of confusion.
Wait a bit
:WAIT
REM 10 second delay
PING 127.0.0.1 -n %delay% >REM
GOTO LOOP
This is the section of code that simply waits the specified number of
seconds. It does this using the ping command which is common for
batch programming since there is no built-in delay or sleep command
like other languages have. The first line is simply a comment, REM
means "Remove" (I think) and is how you comment out lines of code in
batch. As a matter of fact, I should have removed this since it's
not 10 seconds anyway :). The second line pings the localhost 180
times (or whatever the delay variable is set to). The >REM part
means it outputs the results of the ping to, well, I've never seen
"REM" here. Usually you would output it to nul but either way, it's
making sure you don't see the 180 ping results. Now, the 3rd line
tells the processor to go back to the :LOOP label. No matter what.
After the ping, it does the :LOOP section code again.
Execute your vbscript
:CALLVBS
echo It's time!
REM Call VBS here
GOTO WAIT
This is the :CALLVBS section of code. First it outputs "It's
time!". The second line is again, a comment. As you know, you
replace this with your vbscript. After this, the interpreter is told
to go to the :WAIT section of code. Again, it will always do this,
no matter what, after executing the line above it.

batch - simple shutdown script

I wanted to write a simple batch script to shutdown my own computer which will be used when I'm in bed watching a DVD or something.
UPDATE: fixed the code, any other suggestions?
setlocal
#echo off & break off
:input
set /p "minutes=Enter number of minutes to wait until shutdown: "
set "numcheck="&for /f "delims=0123456789" %%i in ("%minutes%") do set "numcheck=%%i"""
if defined numcheck (
echo ERROR: Sorry "%minutes%" is not numeric, please try again & echo.
goto input
)
if %minutes% gtr 315360000 (
echo ERROR: Sorry your input is greater then 10 years, I can't handle that & echo.
goto input
)
set /a "seconds=%minutes%*60"
shutdown.exe /s /f /t "%seconds%"
if errorlevel 1 (
echo ERROR: Could not set shutdown, try again & echo.
goto input
)
:abort
set /p "continue=Your computer is about to shutdown in %minutes% minutes, do you want to abort? (yes/no): "
if %continue% equ yes (
echo Aborting...
shutdown.exe /a
if errorlevel 1 (
echo ERROR: Could not stop shutdown, try again & echo.
goto abort
)
timeout.exe /t 5 /NOBREAK
endlocal
exit /b
) else (
timeout.exe /t 10 /NOBREAK
endlocal
exit /b
)
The most common ways to use the shutdown command are:
shutdown -s — Shuts down.
shutdown -r — Restarts.
shutdown -l — Logs off.
shutdown -h — Hibernates.
Note: There is a common pitfall wherein users think -h means "help" (which it does for every other command-line program... except shutdown.exe, where it means "hibernate"). They then run shutdown -h and accidentally turn off their computers. Watch out for that.
shutdown -i — "Interactive mode". Instead of performing an action, it displays a GUI dialog.
shutdown -a — Aborts a previous shutdown command.
The commands above can be combined with these additional options:
-f — Forces programs to exit. Prevents the shutdown process from getting stuck.
-t <seconds> — Sets the time until shutdown. Use -t 0 to shutdown immediately.
-c <message> — Adds a shutdown message. The message will end up in the Event Log.
-y — Forces a "yes" answer to all shutdown queries.
Note: This option is not documented in any official documentation. It was discovered by these StackOverflow users.
I want to make sure some other really good answers are also mentioned along with this one. Here they are in no particular order.
The -f option from JosephStyons
Using rundll32 from VonC
The Run box from Dean
Remote shutdown from Kip
Shutdown -s -t100
Save it with .bat extenstion
Shutsdown in 100 secx

How to spawn several processes from the Windows shell and wait for them all to complete?

I want to do the following from a Windows batch script:
start proc1.exe
start proc2.exe
...
start procN.exe
<wait for all N processes to complete> <-- What do I put here?
How do I wait for all spawned processes to complete?
This is ugly, but you could wrap each command in another batch file that runs the command and then signals that the command is complete. Your main batch file would call each of those batch files asynchronously and sit in a loop waiting for the signals.
For example:
main.bat
start cmd /c proc1.bat
start cmd /c proc2.bat
:wait
sleep 1
IF NOT EXIST proc1done GOTO wait
IF NOT EXIST proc2done GOTO wait
del proc1done
del proc2done
echo All processes are complete
proc1.bat
proc1.exe
echo Done > proc1done
The sleep command is available in Windows Server 2003 Resource Kit Tools. If you don't have that, you could use a ping on localhost just to slow down that tight loop.
I found a good solution in using an alternative shell called "Yori". You can read more about it and download it from http://www.malsmith.net/yori/. Yori is open source and its code repository is at https://github.com/malxau/yori.
Yori makes it easy to implement parallel process execution and wait for them to finish. In essence, what you need to do is to start the different sub-processes as so-called "jobs" and then use the internal command "wait" to wait for them to finish. You can start any process as a job by adding the special characters "&!" at the end of the command. Something like this:
ping localhost &!
ping someotherhost &!
wait
You can put your Yori-dependent commands in a separate batch-file (with the Yori-batch extension ".ys1") and invoke that from your Windows-batch for example with the following command:
echo Let Yori do the parallel execution of some lengthy operations...
start /wait /b /belownormal yori.exe -c "your-yori-script.ys1"
echo All the lengthy operations are finished, continue with the next steps...
You could do this if you write .NET code or Win32 C/C++ code to start the processes, but there is no way to do it in a batch file. Once you use start to make proc1.exe run asynchronously, there is no batch command that allows you to come back later and wait for it to complete.
But you can do this easily in one of the scripting languages designed for batch work, Python, WSH, etc.
For example, here's a simple script using Windows Script Host. WSH is included in all versions of Windows since Windows 98. So this script should run anywhere.
This script starts two programs and waits for them both to finish. Save it as as start2.wsf. Then just use it in your batch file:
start2.wsf "prog1.exe" "prog2.exe"
<package>
<job id="Start 2 Procs">
<runtime>
<description>Start 2 programs and wait for them both to finish.
</description>
<unnamed
name="program"
helpstring="the program to run"
many="false"
required="2"
/>
<example>
Example: Start2.wsf "cl -c foo.obj" "cl -c bar.obj"
</example>
</runtime>
<script language="JScript">
if (WScript.Arguments.length < 2)
{
WScript.Arguments.ShowUsage();
WScript.Quit();
}
var proc1 = WScript.Arguments.Unnamed.Item(0);
var proc2 = WScript.Arguments.Unnamed.Item(1);
var Shell = WScript.CreateObject("WScript.Shell");
var oProc1 = Shell.Exec(proc1);
var oProc2 = Shell.Exec(proc2);
while (oProc1.Status == 0 && oProc2.Status == 0)
{
WScript.Sleep(1000);
}
</script>
</job>
</package>
Typically you would do something like this using Python, but here it goes (inspired by this post and others):
calcFromList.bat < DesiredBatchFile > < TxtFile > [--async [SleepTimeBetweenSpawns]]
It will spawn one process for each line in TxtFile (the line is used to specify the individual parameters for the batch file).
calcFromList.bat:
echo off
pushd \
%~d0
cd "%~dp0"
set CALL_BAT="%~1"
set FILE_CONTAINING_LIST="%~2"
if %CALL_BAT%=="" (goto badval)
if %FILE_CONTAINING_LIST%=="" (goto badval2)
if "%3"=="--async" goto async
for /f "delims=¬" %%X in ('type %FILE_CONTAINING_LIST%') do (call %CALL_BAT% %%X)
goto end
:async
set /a AsyncCountNum=1
set SLEEP_VALUE_S=0
if not "%4"=="" (set SLEEP_VALUE_S=%4)
set AsyncParamBat=%CALL_BAT%
:: Find unique id even if called simultaneously (using simple collision detection)
:newid
timeout /t 1 /nobreak > NUL
set AsyncRand=%RANDOM:~-1%%RANDOM:~-2%%RANDOM:~-3%
set AsyncCountFilePrefix="%FILE_CONTAINING_LIST:"=%__%AsyncRand%"
set AsyncCollisionText="%~1;%~2;%~3;%~4;"
IF EXIST "%AsyncCountFilePrefix:"=%0" GOTO newid
echo %AsyncCollisionText% > "%AsyncCountFilePrefix:"=%_init_async_done.txt"
set /p AsyncCheckColision=<"%AsyncCountFilePrefix:"=%_init_async_done.txt"
if "%AsyncCollisionText:"=% "=="%AsyncCheckColision:"=%" GOTO idfound
timeout /t 1 /nobreak > NUL
GOTO newid
:idfound
echo Beginning spawning of processes (id = %AsyncRand%)...
for /f "delims=¬" %%X in ('type %FILE_CONTAINING_LIST%') do (set AsyncParamCall="%%~X" & start "Batch (from id %AsyncRand%)" /D "%~dp0" "cmd /c asyncExec.bat" & set /a AsyncCountNum+=1 & timeout /t %SLEEP_VALUE_S% /nobreak > NUL)
set /a AsyncCountNum-=1
echo All %AsyncCountNum% processes spawned, waiting for their completion...
:wait
timeout /t 2 /nobreak > NUL
for /l %%x in (1, 1, %AsyncCountNum%) do (IF NOT EXIST "%AsyncCountFilePrefix:"=%_%%x_tmp_async_done.txt" GOTO wait )
echo Finished, cleaning up...
for /l %%x in (1, 1, %AsyncCountNum%) do (del /F /Q "%AsyncCountFilePrefix:"=%_%%x_tmp_async_done.txt")
del /F /Q "%AsyncCountFilePrefix:"=%_init_async_done.txt"
goto end
start "Calib for %~TARGET_FOLDER%" /D "%~dp0" "cmd /k calibCamsSequence.bat"
goto end
:badval
echo No bat file specified! (first parameter)
goto end
:badval2
echo No list file specified! (second parameter)
:end
popd
asyncExec.bat:
#call %AsyncParamBat% %AsyncParamCall%
#echo "Done at %DATE% %TIME%" > "%AsyncCountFilePrefix:"=%_%AsyncCountNum%_tmp_async_done.txt"

How do I measure execution time of a command on the Windows command line?

Is there a built-in way to measure execution time of a command on the Windows command line?
PowerShell has a cmdlet for this called Measure-Command. You'll have to ensure that PowerShell is available on the machine that runs it.
PS> Measure-Command { echo hi }
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 1318
TotalDays : 1.52546296296296E-09
TotalHours : 3.66111111111111E-08
TotalMinutes : 2.19666666666667E-06
TotalSeconds : 0.0001318
TotalMilliseconds : 0.1318
Measure-Command captures the command's output. You can redirect the output back to your console using Out-Default:
PS> Measure-Command { echo hi | Out-Default }
hi
Days : 0
...
As Makotoe commented, Measure-Command returns a TimeSpan object, so the measured time is printed as a bunch of fields. You can format the object into a timestamp string using ToString():
PS> (Measure-Command { echo hi | Out-Default }).ToString()
hi
00:00:00.0001318
If the command inside Measure-Command changes your console text color, use [Console]::ResetColor() to reset it back to normal.
If you want
To measure execution time down to the hundredth of a second in (hh:mm:ss.ff format)
To not have to download and install a resource pack
To look like a huge DOS nerd (who doesn't)
Try copying the following script into a new batch file (e.g. timecmd.bat):
#echo off
#setlocal
set start=%time%
:: Runs your command
cmd /c %*
set end=%time%
set options="tokens=1-4 delims=:.,"
for /f %options% %%a in ("%start%") do set start_h=%%a&set /a start_m=100%%b %% 100&set /a start_s=100%%c %% 100&set /a start_ms=100%%d %% 100
for /f %options% %%a in ("%end%") do set end_h=%%a&set /a end_m=100%%b %% 100&set /a end_s=100%%c %% 100&set /a end_ms=100%%d %% 100
set /a hours=%end_h%-%start_h%
set /a mins=%end_m%-%start_m%
set /a secs=%end_s%-%start_s%
set /a ms=%end_ms%-%start_ms%
if %ms% lss 0 set /a secs = %secs% - 1 & set /a ms = 100%ms%
if %secs% lss 0 set /a mins = %mins% - 1 & set /a secs = 60%secs%
if %mins% lss 0 set /a hours = %hours% - 1 & set /a mins = 60%mins%
if %hours% lss 0 set /a hours = 24%hours%
if 1%ms% lss 100 set ms=0%ms%
:: Mission accomplished
set /a totalsecs = %hours%*3600 + %mins%*60 + %secs%
echo command took %hours%:%mins%:%secs%.%ms% (%totalsecs%.%ms%s total)
Usage
If you put timecmd.bat in a directory in your path, you can call it from anywhere like this:
timecmd [your command]
E.g.
C:\>timecmd pause
Press any key to continue . . .
command took 0:0:1.18
If you want to do output redirection, you can quote the command like this:
timecmd "dir c:\windows /s > nul"
This should handle commands that run from before- to after-midnight, but the output will be wrong if your command runs for 24 hours or more.
Hehe, the most simple solution might be this:
echo %time%
YourApp.exe
echo %time%
This works on every Windows out of the box.
In case of an application using console output, it might be convenient to store the starting time in a temporary variable:
set startTime=%time%
YourApp.exe
echo Start Time: %startTime%
echo Finish Time: %time%
Just a little expansion of the answer from Casey.K about using the Measure-Command from PowerShell:
You can invoke PowerShell from the standard command prompt, like this:
powershell -Command "Measure-Command {echo hi}"
This will eat the standard output, but you can prevent that by adding | Out-Default like this from PowerShell:
Measure-Command {echo hi | Out-Default}
Or from a command prompt:
powershell -Command "Measure-Command {echo hi | Out-Default}"
Of course, you're free to wrap this in a script file *.ps1 or *.bat.
If you are using Windows 2003 (note that windows server 2008 and later are not supported) you can use The Windows Server 2003 Resource Kit, which contains timeit.exe that displays detailed execution stats. Here is an example, timing the command "timeit -?":
C:\>timeit timeit -?
Invalid switch -?
Usage: TIMEIT [-f filename] [-a] [-c] [-i] [-d] [-s] [-t] [-k keyname | -r keyname] [-m mask] [commandline...]
where: -f specifies the name of the database file where TIMEIT
keeps a history of previous timings. Default is .\timeit.dat
-k specifies the keyname to use for this timing run
-r specifies the keyname to remove from the database. If
keyname is followed by a comma and a number then it will
remove the slowest (positive number) or fastest (negative)
times for that keyname.
-a specifies that timeit should display average of all timings
for the specified key.
-i specifies to ignore non-zero return codes from program
-d specifies to show detail for average
-s specifies to suppress system wide counters
-t specifies to tabular output
-c specifies to force a resort of the data base
-m specifies the processor affinity mask
Version Number: Windows NT 5.2 (Build 3790)
Exit Time: 7:38 am, Wednesday, April 15 2009
Elapsed Time: 0:00:00.000
Process Time: 0:00:00.015
System Calls: 731
Context Switches: 299
Page Faults: 515
Bytes Read: 0
Bytes Written: 0
Bytes Other: 298
You can get TimeIt in the Windows 2003 Resource Kit. It's not available for direct download from the Microsoft Download Center, but one can still get it from the archive.org - Windows Server 2003 Resource Kit Tools.
The one-liner I use in Windows Server 2008 R2 is:
cmd /v:on /c "echo !TIME! & *mycommand* & echo !TIME!"
So long as mycommand doesn't require quotes (which screws with cmd's quote processing). The /v:on is to allow for the two different TIME values to be evaluated independently rather than once at the execution of the command.
If you have a command window open and call the commands manually, you can display a timestamp on each prompt, e.g.
prompt $d $t $_$P$G
It gives you something like:
23.03.2009 15:45:50,77
C:\>
If you have a small batch script that executes your commands, have an empty line before each command, e.g.
(empty line)
myCommand.exe
(next empty line)
myCommand2.exe
You can calculate the execution time for each command by the time information in the prompt. The best would probably be to pipe the output to a textfile for further analysis:
MyBatchFile.bat > output.txt
Since others are recommending installing things like freeware and PowerShell, you could also install Cygwin, which would give you access to many basic Unix commands like time:
abe#abe-PC:~$ time sleep 5
real 0m5.012s
user 0m0.000s
sys 0m0.000s
Not sure how much overhead Cygwin adds.
Not quite as elegant as some of the functionality on Unix, but create a cmd file which looks like:
#echo off
time < nul
yourexecutable.exe > c:\temp\output.txt
time < nul
rem on newer windows system you can try time /T
That will display the start and stop times like so:
The current time is: 10:31:57.92
Enter the new time:
The current time is: 10:32:05.94
Enter the new time:
I use freeware called "GS Timer".
Just make a batch file like this:
timer
yourapp.exe
timer /s
If you need a set of times, just pipe the output of timer /s into a .txt file.
You can get it here: Gammadyne's Free DOS Utilities
The resolution is 0.1 seconds.
I'm using Windows XP and for some reason timeit.exe does not work for me. I found another alternative - PTIME. This works very well.
http://www.pc-tools.net/win32/ptime/
Example -
C:\> ptime
ptime 1.0 for Win32, Freeware - http://www.pc-tools.net/
Copyright(C) 2002, Jem Berkes <jberkes#pc-tools.net>
Syntax: ptime command [arguments ...]
ptime will run the specified command and measure the execution time
(run time) in seconds, accurate to 5 millisecond or better. It is an
automatic process timer, or program timer.
C:\> ptime cd
ptime 1.0 for Win32, Freeware - http://www.pc-tools.net/
Copyright(C) 2002, Jem Berkes <jberkes#pc-tools.net>
=== cd ===
C:\
Execution time: 0.015 s
As long as it doesn't last longer than 24hours...
#echo off
set starttime=%TIME%
set startcsec=%STARTTIME:~9,2%
set startsecs=%STARTTIME:~6,2%
set startmins=%STARTTIME:~3,2%
set starthour=%STARTTIME:~0,2%
set /a starttime=(%starthour%*60*60*100)+(%startmins%*60*100)+(%startsecs%*100)+(%startcsec%)
:TimeThis
ping localhost
set endtime=%time%
set endcsec=%endTIME:~9,2%
set endsecs=%endTIME:~6,2%
set endmins=%endTIME:~3,2%
set endhour=%endTIME:~0,2%
if %endhour% LSS %starthour% set /a endhour+=24
set /a endtime=(%endhour%*60*60*100)+(%endmins%*60*100)+(%endsecs%*100)+(%endcsec%)
set /a timetaken= ( %endtime% - %starttime% )
set /a timetakens= %timetaken% / 100
set timetaken=%timetakens%.%timetaken:~-2%
echo.
echo Took: %timetaken% sec.
There's also TimeMem (March 2012):
This is a Windows utility which executes a program and displays its
execution time, memory usage, and IO statistics. It is similar in
functionality to the Unix time utility.
Here is a
Postfix timer version:
Usage example:
timeout 1 | TimeIt.cmd
Execution took ~969 milliseconds.
Copy & paste this into some editor like for example Notepad++ and save it as TimeIt.cmd:
:: --- TimeIt.cmd ----
#echo off
setlocal enabledelayedexpansion
call :ShowHelp
:: Set pipeline initialization time
set t1=%time%
:: Wait for stdin
more
:: Set time at which stdin was ready
set t2=!time!
:: Calculate difference
Call :GetMSeconds Tms1 t1
Call :GetMSeconds Tms2 t2
set /a deltaMSecs=%Tms2%-%Tms1%
echo Execution took ~ %deltaMSecs% milliseconds.
endlocal
goto :eof
:GetMSeconds
Call :Parse TimeAsArgs %2
Call :CalcMSeconds %1 %TimeAsArgs%
goto :eof
:CalcMSeconds
set /a %1= (%2 * 3600*1000) + (%3 * 60*1000) + (%4 * 1000) + (%5)
goto :eof
:Parse
:: Mask time like " 0:23:29,12"
set %1=!%2: 0=0!
:: Replace time separators with " "
set %1=!%1::= !
set %1=!%1:.= !
set %1=!%1:,= !
:: Delete leading zero - so it'll not parsed as octal later
set %1=!%1: 0= !
goto :eof
:ShowHelp
echo %~n0 V1.0 [Dez 2015]
echo.
echo Usage: ^<Command^> ^| %~nx0
echo.
echo Wait for pipe getting ready... :)
echo (Press Ctrl+Z ^<Enter^> to Cancel)
goto :eof
^ - Based on 'Daniel Sparks' Version
Depending on the version of Windows you're using, just running bash will put you into Bash mode. This will allow you to use a bunch of commands that are not available on PowerShell directly (like the time command). Timing your command is now as easy as executing:
# The clause <your-command> (without the angle brackets) denotes the command you want to run.
$ time <your-command>
Note: You can easily quit from Bash mode and return back into your mainstream shell by running exit while in Bash mode.
This worked for me perfectly (Windows 10) after trying out other methods (like Measure-Command) which sometimes produce undesired stats. Hope this works for you as well.
An alternative to measure-time is simply "Get-Date". You don't have that hassle with forwarding output and so on.
$start = Get-Date
[System.Threading.Thread]::Sleep(1500)
$(Get-Date) - $start
Output:
Days : 0
Hours : 0
Minutes : 0
Seconds : 1
Milliseconds : 506
Ticks : 15060003
TotalDays : 1.74305590277778E-05
TotalHours : 0.000418333416666667
TotalMinutes : 0.025100005
TotalSeconds : 1.5060003
TotalMilliseconds : 1506.0003
This is a one-liner which avoids delayed expansion, which could disturb certain commands:
cmd /E /C "prompt $T$$ & echo.%TIME%$ & COMMAND_TO_MEASURE & for %Z in (.) do rem/ "
The output is something like:
14:30:27.58$
...
14:32:43.17$ rem/
For long-term tests replace $T by $D, $T and %TIME% by %DATE%, %TIME% to include the date.
To use this inside of a batch file, replace %Z by %%Z.
Update
Here is an improved one-liner (without delayed expansion too):
cmd /E /C "prompt $D, $T$$ & (for %# in (.) do rem/ ) & COMMAND_TO_MEASURE & for %# in (.) do prompt"
The output looks similar to this:
2015/09/01, 14:30:27.58$ rem/
...
2015/09/01, 14:32:43.17$ prompt
This approach does not include the process of instancing a new cmd in the result, nor does it include the prompt command(s).
In case anyone else has come here looking for an answer to this question, there's a Windows API function called GetProcessTimes(). It doesn't look like too much work to write a little C program that would start the command, make this call, and return the process times.
In the directory where your program is, type notepad mytimer.bat, click 'yes' to create a new file.
Paste the code below, replacing YourApp.exe with your program, then save.
#echo off
date /t
time /t
YourApp.exe
date /t
time /t
Type mytimer.bat in the command line then press Enter.
Here is my method, no conversion and no ms. It is useful to determine encoding durations (limited to 24 hours though):
#echo off
:start
REM Start time storage
set ST=%time%
echo Process started at %ST%
echo.
echo.
REM Your commands
REM Your commands
REM Your commands
:end
REM Start Time Definition
for /f "tokens=1-3 delims=:" %%a in ("%ST%") do set /a h1=%%a & set /a m1=%%b & set /a s1=%%c
REM End Time Definition
for /f "tokens=1-3 delims=:" %%a in ("%TIME%") do set /a h2=%%a & set /a m2=%%b & set /a s2=%%c
REM Difference
set /a h3=%h2%-%h1% & set /a m3=%m2%-%m1% & set /a s3=%s2%-%s1%
REM Time Adjustment
if %h3% LSS 0 set /a h3=%h3%+24
if %m3% LSS 0 set /a m3=%m3%+60 & set /a h3=%h3%-1
if %s3% LSS 0 set /a s3=%s3%+60 & set /a m3=%m3%-1
echo Start : %ST%
echo End : %time%
echo.
echo Total : %h3%:%m3%:%s3%
echo.
pause
my code gives you the running time in milliseconds, up to 24 hrs, it is locale insensitive, and accounts for negative values if code runs through midnight. it uses delayed expansion, and should be saved in a cmd/bat file.
before your code:
SETLOCAL EnableDelayedExpansion
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /format:list') do set t=%%I
set /a t1 = %t:~8,1%*36000 + %t:~9,1%*3600 + %t:~10,1%*600 + %t:~11,1%*60 + %t:~12,1%*10 + %t:~13,1% && set t1=!t1!%t:~15,3%
after your code:
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /format:list') do set t=%%I
set /a t2 = %t:~8,1%*36000 + %t:~9,1%*3600 + %t:~10,1%*600 + %t:~11,1%*60 + %t:~12,1%*10 + %t:~13,1% && set t2=!t2!%t:~15,3%
set /a t2-=t1 && if !t2! lss 0 set /a t2+=24*3600000
if you want running time in HH:mm:ss.000 format, add:
set /a "h=t2/3600000,t2%%=3600000,m=t2/60000,t2%%=60000" && set t2=00000!t2!&& set t2=!t2:~-5!
if %h% leq 9 (set h=0%h%) && if %m% leq 9 (set m=0%m%)
set t2=%h%:%m%:%t2:~0,2%.%t2:~2,3%
ENDLOCAL
variable t2 holds your running time, you can echo %t2% to display it.
This is a comment/edit to Luke Sampson's nice timecmd.bat and reply to
For some reason this only gives me output in whole seconds... which for me is useless. I mean that I run timecmd pause, and it always results in 1.00 sec, 2.00 sec, 4.00 sec... even 0.00 sec! Windows 7. – Camilo Martin Sep 25 '13 at 16:00 "
On some configurations the delimiters may differ. The following change should cover atleast most western countries.
set options="tokens=1-4 delims=:,." (added comma)
The %time% milliseconds work on my system after adding that ','
(*because site doesn't allow anon comment and doesn't keep good track of identity even though I always use same guest email which combined with ipv6 ip and browser fingerprint should be enough to uniquely identify without password)
Another approach with powershell:
#echo off
for /f %%t in ('powershell "(get-date).tofiletime()"') do set mst=%%t
rem some commands
powershell ((get-date).tofiletime() - %mst%)
this will print the execution time in milliseconds.
If you have CMake installed, you can just run following command.
cmake -E time <the_command_to_measure_run_time>
#echo off & setlocal
set start=%time%
REM Do stuff to be timed here.
REM Alternatively, uncomment the line below to be able to
REM pass in the command to be timed when running this script.
REM cmd /c %*
set end=%time%
REM Calculate time taken in seconds, to the hundredth of a second.
REM Assumes start time and end time will be on the same day.
set options="tokens=1-4 delims=:."
for /f %options% %%a in ("%start%") do (
set /a start_s="(100%%a %% 100)*3600 + (100%%b %% 100)*60 + (100%%c %% 100)"
set /a start_hs=100%%d %% 100
)
for /f %options% %%a in ("%end%") do (
set /a end_s="(100%%a %% 100)*3600 + (100%%b %% 100)*60 + (100%%c %% 100)"
set /a end_hs=100%%d %% 100
)
set /a s=%end_s%-%start_s%
set /a hs=%end_hs%-%start_hs%
if %hs% lss 0 (
set /a s=%s%-1
set /a hs=100%hs%
)
if 1%hs% lss 100 set hs=0%hs%
echo.
echo Time taken: %s%.%hs% secs
echo.
The following script uses only "cmd.exe" and outputs the number of milliseconds from the time a pipeline is created to the time that the process preceding the script exits. i.e., Type your command, and pipe the to the script. Example: "timeout 3 | runtime.cmd" should yield something like "2990." If you need both the runtime output and the stdin output, redirect stdin before the pipe - ex: "dir /s 1>temp.txt | runtime.cmd" would dump the output of the "dir" command to "temp.txt" and would print the runtime to the console.
:: --- runtime.cmd ----
#echo off
setlocal enabledelayedexpansion
:: find target for recursive calls
if not "%1"=="" (
shift /1
goto :%1
exit /b
)
:: set pipeline initialization time
set t1=%time%
:: wait for stdin
more > nul
:: set time at which stdin was ready
set t2=!time!
::parse t1
set t1=!t1::= !
set t1=!t1:.= !
set t1=!t1: 0= !
:: parse t2
set t2=!t2::= !
set t2=!t2:.= !
set t2=!t2: 0= !
:: calc difference
pushd %~dp0
for /f %%i in ('%0 calc !t1!') do for /f %%j in ('%0 calc !t2!') do (
set /a t=%%j-%%i
echo !t!
)
popd
exit /b
goto :eof
:calc
set /a t=(%1*(3600*1000))+(%2*(60*1000))+(%3*1000)+(%4)
echo !t!
goto :eof
endlocal
The answer of driblio can be made a little shorter (though not much readable)
#echo off
:: Calculate the start timestamp
set _time=%time%
set /a _hours=100%_time:~0,2%%%100,_min=100%_time:~3,2%%%100,_sec=100%_time:~6,2%%%100,_cs=%_time:~9,2%
set /a _started=_hours*60*60*100+_min*60*100+_sec*100+_cs
:: yourCommandHere
:: Calculate the difference in cSeconds
set _time=%time%
set /a _hours=100%_time:~0,2%%%100,_min=100%_time:~3,2%%%100,_sec=100%_time:~6,2%%%100,_cs=%_time:~9,2%
set /a _duration=_hours*60*60*100+_min*60*100+_sec*100+_cs-_started
:: Populate variables for rendering (100+ needed for padding)
set /a _hours=_duration/60/60/100,_min=100+_duration/60/100%%60,_sec=100+(_duration/100%%60%%60),_cs=100+_duration%%100
echo Done at: %_time% took : %_hours%:%_min:~-2%:%_sec:~-2%.%_cs:~-2%
::prints something like:
::Done at: 12:37:53,70 took: 0:02:03.55
To the remark of Luke Sampson this version is octal safe, though the task should be completed in 24 hours.
Having Perl installed the hires solution available, run:
C:\BATCH>time.pl "echo Fine result"
0.01063
Fine result
STDERR comes before measured seconds
#!/usr/bin/perl -w
use Time::HiRes qw();
my $T0 = [ Time::HiRes::gettimeofday ];
my $stdout = `#ARGV`;
my $time_elapsed = Time::HiRes::tv_interval( $T0 );
print $time_elapsed, "\n";
print $stdout;
A solution using pure PHP for cmd and one env. variable:
#echo off
setlocal enableextensions
REM set start time env var
FOR /F "tokens=* USEBACKQ" %%F IN (`php -r "echo microtime(true);"`) DO ( SET start_time=%%F )
## PUT_HERE_THE_COMMAND_TO_RUN ##
REM echo elapsed time
php -r "echo 'elapsed: ' . (round(microtime(true) - trim(getenv('start_time')), 2)) . ' seconds' . mb_convert_encoding('
', 'UTF-8', 'HTML-ENTITIES');"
no need for cygwin or non-trusted utilities. Usefull when PHP is locally available
precision and output format can be easily tweaked
the same idea can be ported for PowerShell
Using a sub to return time in hundredths of second
::tiemeit.cmd
#echo off
Setlocal EnableDelayedExpansion
call :clock
::call your_command or more > null to pipe this batch after your_command
call :clock
echo %timed%
pause
goto:eof
:clock
if not defined timed set timed=0
for /F "tokens=1-4 delims=:.," %%a in ("%time%") do (
set /A timed = "(((1%%a - 100) * 60 + (1%%b - 100)) * 60 + (1%%c - 100)) * 100 + (1%%d - 100)- %timed%"
)
goto:eof

Resources