Windows batch file - check if file has been modified - windows

I'm configuring a windows machine to continuously run a powerpoint presentation. The ppt file is located on a samba share (windows file sharing) and will be updated periodically. I need a way to make a batch file that will restart the ppt slide show if the file has been changed. The batch script will run on a a regular interval, and will hopefully check to see if the file has been updated, and re-start the slideshow if it has.
If there is a way to do this in powershell, that would work too.

Well, in a batch, the easiest way I would think of would be to periodically check whether the file's last modification date and/or its size has changed.
You can get both via the following:
for %%X in (myfile) do set size=%%~zX&set filetime=%%~tX
You can then cache those values and compare whether they have changed since the last iteration. Using a delay (a few seconds maybe) via
ping -n 11 localhost >nul 2>nul
(for 10 seconds delay) can help in not checking too often.
So, it might look a little like the following:
#echo off
setlocal
set FileName=MyPresentation.pptx
set FileTime=-
:loop
for %%X in (%FileName%) do (
if %FileTime% NEQ %%~tX (
rem just an example
taskkill /f powerpnt.exe
start %FileName%
)
set FileTime=%%~tX
)
rem wait 5 seconds before checking again
ping -n 6 localhost >nul 2>nul
goto :loop
In PowerShell the code wouldn't look too different, except that you get to the relevant properties a little easier:
$FileName = "MyPresentation.pptx"
$FileTime = Get-Date
# endless loop
for () {
$file = Get-Item $FileName
if ($FileTime -ne $file.LastWriteTime) {
Get-Process powerpnt* | Stop-Process
Invoke-Item $file
}
$FileTime = $file.LastWriteTime
Start-Sleep 5
}

Try the code below. It checks for the current time and checks when the file was last modified. If the two values are the same it is assumed the file was altered.
#echo off &setlocal
TITLE File Monitor
Set file=Test.txt
:CheckforAlter
Set modif_time=
Set allm=
cls
for /f "tokens=1-3 delims=:,. " %%A in ("%time%") do (
set "Hour=%%A"
set "Min=%%B"
set "Sec=%%C"
)
set /a Hour = Hour %% 12
if %Hour%==0 set "Hour=12"
set "Allm=%Hour%:%Min%:%Sec%"
for /f %%i in ('"forfiles /m %file% /c "cmd /c echo #ftime" "') do set modif_time=%%i
echo.
echo.
IF %modif_time%==%Allm% (
echo File was altered.
start "" "%file%"
Timeout /t 1 >nul
)
echo file wasn't modified.
GOTO CheckforAlter

Found this:
#echo off
if not "%~1"=="" echo Modified date of %~1 is %~t1
on Experts exchange. Maybe a good point to start from.

Related

download file from FTP and store those files in daily dated folder [duplicate]

I am writing a script using ftp.exe to download files from an FTP server, it works at first. But the version I wrote was suited for only one file and the current date. My script is below:
echo user>>ftp.txt
echo password>>ftp.txt
set prefix=%date:~0,10%
set "name=%prefix%.txt"
echo get %name% >> ftp.txt
echo bye >> ftp.txt
ftp -s:ftp.txt ftpserver.com
del ftp.txt
But now there are more than one file named like aa-bb-2011-09-13.0.log,
aa-bb-2011-09-13.1.log,
aa-bb-2011-09-13.10.log. The last number is a serial number, it could be 0, 1, 2, 3...
How could download these files by batch script? How to modify my script to download more than one file (the number is unknown) which file name pattern is yesterday?
In terms of downloading multiple files, use mget instead of get. The former allows you to specify wildcards for getting rather than specific files.
You'll just have to construct the "name" with a wildcard pattern, and make sure you have a prompt in your script before mget otherwise it will ask for confirmation on every file.
This is untested, but it's probably as simple as changing:
echo get %name% >> ftp.txt
to something like:
echo prompt>>ftp.txt
echo mget *%prefix%*>>ftp.txt
In terms of getting yesterdays date, you can use the following script. It's pretty complex compared to what you would do in, for example bash, but it works.
#setlocal enableextensions enabledelayedexpansion
#echo off
rem Get the date from WMI (on one line).
for /f "skip=2 tokens=2-7 delims=," %%A in ('wmic
path win32_localtime get day^,month^,year^ /format:csv') do (
set /a "yest_yyyy = %%C"
set /a "yest_mm = %%B"
set /a "yest_dd = %%A"
)
rem Not the first of the month, just decrement day.
if not %yest_dd%==1 (
set /a yest_dd = yest_dd - 1
goto done
)
rem Jan 1, set to Dec 31 previous year.
if %yest_mm%==1 (
set /a "yest_dd = 31"
set /a "yest_mm = 12"
set /a "yest_yyyy = yest_yyyy - 1"
goto :done
)
rem Any other day, decrement month.
set /a "yest_mm = yest_mm - 1"
rem Need to find last day, default to 31.
set dim=31
rem Apr/Jun/Sep/Nov all have 30 days. Feb gets special handling.
if %yest_mm%==4 set dim=30
if %yest_mm%==6 set dim=30
if %yest_mm%==9 set dim=30
if %yest_mm%==11 set dim=30
if not %yest_mm%==2 goto :got_dim
rem Default Feb to 28 then use rules to override.
set dim=28
set /a "divid=yest_yyyy%%400"
if "%divid%"=="0" goto daysinmonth_29days
set /a "divid=yest_yyyy%%100"
if "%divid%"=="0" goto :done
set /a "divid=yest_yyyy%%4"
if not "%divid%"=="0" goto :done
rem Adjust to 29 days.
:daysinmonth_29days
set dim=29
:done
rem Pad out and return value.
if %yest_mm% lss 10 set yest_mm=0%yest_mm%
if %yest_dd% lss 10 set yest_dd=0%yest_dd%
set yesterday=%yest_yyyy%-%yest_mm%-%yest_dd%
endlocal && set yesterday=%yesterday%
It will set the yesterday environment variable to the format YYYY-MM-DD so that you can use it in your current script. Simply invoke call yesterday.cmd and then use the environment variable.
It's a pretty complex task to implement with Windows batch-file and the built-in FTP client (ftp.exe).
It would be more easier with PowerShell.
And even easier using a more capable FTP client, like the latest version of WinSCP FTP client.
If you want to download files based on a pattern in a file name, this will do:
winscp.com /ini=nul /log=yesterday.log /command ^
"open ftp://username:password#ftp.example.com/" ^
"get /remote/path/*%%TIMESTAMP-1D#yyyy-mm-dd%%* C:\local\path\" ^
"exit"
This uses the %TIMESTAMP% syntax
If you want to download based on a file modification time, use a file mask with a time-constraint:
winscp.com /ini=nul /log=yesterday.log /command ^
"open ftp://username:password#ftp.example.com/" ^
"get /remote/path/*>=yesterday<today C:\local\path\" ^
"exit"
The >=yesterday<today syntax is supported by WinSCP 5.15 and newer.
In older versions of WinSCP, you can again use %TIMESTAMP% syntax, particularly >=%%TIMESTAMP-1D#yyyy-mm-dd%%<%%TIMESTAMP#yyyy-mm-dd%%, instead of >=yesterday<today.
(I'm the author of WinSCP)
This is a sample FTP script that does almost exactly what you need but it uses a 3rd party client instead of the one that comes free with Windows: http://kb.robo-ftp.com/script_library/show/45
Maybe you can convert it.

Windows batch script to download yesterday files

I am writing a script using ftp.exe to download files from an FTP server, it works at first. But the version I wrote was suited for only one file and the current date. My script is below:
echo user>>ftp.txt
echo password>>ftp.txt
set prefix=%date:~0,10%
set "name=%prefix%.txt"
echo get %name% >> ftp.txt
echo bye >> ftp.txt
ftp -s:ftp.txt ftpserver.com
del ftp.txt
But now there are more than one file named like aa-bb-2011-09-13.0.log,
aa-bb-2011-09-13.1.log,
aa-bb-2011-09-13.10.log. The last number is a serial number, it could be 0, 1, 2, 3...
How could download these files by batch script? How to modify my script to download more than one file (the number is unknown) which file name pattern is yesterday?
In terms of downloading multiple files, use mget instead of get. The former allows you to specify wildcards for getting rather than specific files.
You'll just have to construct the "name" with a wildcard pattern, and make sure you have a prompt in your script before mget otherwise it will ask for confirmation on every file.
This is untested, but it's probably as simple as changing:
echo get %name% >> ftp.txt
to something like:
echo prompt>>ftp.txt
echo mget *%prefix%*>>ftp.txt
In terms of getting yesterdays date, you can use the following script. It's pretty complex compared to what you would do in, for example bash, but it works.
#setlocal enableextensions enabledelayedexpansion
#echo off
rem Get the date from WMI (on one line).
for /f "skip=2 tokens=2-7 delims=," %%A in ('wmic
path win32_localtime get day^,month^,year^ /format:csv') do (
set /a "yest_yyyy = %%C"
set /a "yest_mm = %%B"
set /a "yest_dd = %%A"
)
rem Not the first of the month, just decrement day.
if not %yest_dd%==1 (
set /a yest_dd = yest_dd - 1
goto done
)
rem Jan 1, set to Dec 31 previous year.
if %yest_mm%==1 (
set /a "yest_dd = 31"
set /a "yest_mm = 12"
set /a "yest_yyyy = yest_yyyy - 1"
goto :done
)
rem Any other day, decrement month.
set /a "yest_mm = yest_mm - 1"
rem Need to find last day, default to 31.
set dim=31
rem Apr/Jun/Sep/Nov all have 30 days. Feb gets special handling.
if %yest_mm%==4 set dim=30
if %yest_mm%==6 set dim=30
if %yest_mm%==9 set dim=30
if %yest_mm%==11 set dim=30
if not %yest_mm%==2 goto :got_dim
rem Default Feb to 28 then use rules to override.
set dim=28
set /a "divid=yest_yyyy%%400"
if "%divid%"=="0" goto daysinmonth_29days
set /a "divid=yest_yyyy%%100"
if "%divid%"=="0" goto :done
set /a "divid=yest_yyyy%%4"
if not "%divid%"=="0" goto :done
rem Adjust to 29 days.
:daysinmonth_29days
set dim=29
:done
rem Pad out and return value.
if %yest_mm% lss 10 set yest_mm=0%yest_mm%
if %yest_dd% lss 10 set yest_dd=0%yest_dd%
set yesterday=%yest_yyyy%-%yest_mm%-%yest_dd%
endlocal && set yesterday=%yesterday%
It will set the yesterday environment variable to the format YYYY-MM-DD so that you can use it in your current script. Simply invoke call yesterday.cmd and then use the environment variable.
It's a pretty complex task to implement with Windows batch-file and the built-in FTP client (ftp.exe).
It would be more easier with PowerShell.
And even easier using a more capable FTP client, like the latest version of WinSCP FTP client.
If you want to download files based on a pattern in a file name, this will do:
winscp.com /ini=nul /log=yesterday.log /command ^
"open ftp://username:password#ftp.example.com/" ^
"get /remote/path/*%%TIMESTAMP-1D#yyyy-mm-dd%%* C:\local\path\" ^
"exit"
This uses the %TIMESTAMP% syntax
If you want to download based on a file modification time, use a file mask with a time-constraint:
winscp.com /ini=nul /log=yesterday.log /command ^
"open ftp://username:password#ftp.example.com/" ^
"get /remote/path/*>=yesterday<today C:\local\path\" ^
"exit"
The >=yesterday<today syntax is supported by WinSCP 5.15 and newer.
In older versions of WinSCP, you can again use %TIMESTAMP% syntax, particularly >=%%TIMESTAMP-1D#yyyy-mm-dd%%<%%TIMESTAMP#yyyy-mm-dd%%, instead of >=yesterday<today.
(I'm the author of WinSCP)
This is a sample FTP script that does almost exactly what you need but it uses a 3rd party client instead of the one that comes free with Windows: http://kb.robo-ftp.com/script_library/show/45
Maybe you can convert it.

Print request upon new file in folder

I've got the following problem:
I need to make something that checks to see whether a file has been added to a specific folder, ifso this file needs to be printed. I heard Windows maybe has something similar built in?
*Program constantly checks whether a file has been added*
File has been added
File gets printed immediately
I have found solutions, but you need to pay for them.
UPDATE
"Code supplied by Vik"
:start
set SECONDS=60
SET FILENAME=*.jpg
IF EXIST %FILENAME% MSPAINT /p %FILENAME%
choice /C a /T %SECONDS% /D a
DEL /Q %FILENAME%
goto :start
"Edits: COPY *.JPG file to a different folder (E.G. ImageHistory)"
"Edits: DELETE local *.JPG file leaving the monitor folder empty"
Any tips or help are welcome!
This batch file will check if the file printme.jpg exists every 60 seconds. If it exists, it will use the built-in MSPAINT program to print it. Feel free to configure SECONDS and FILENAME to suit your environment.
:start
set SECONDS=60
SET FILENAME=printme.jpg
IF EXIST %FILENAME% MSPAINT /p %FILENAME%
choice /C a /T %SECONDS% /D a
goto :start
Additional mods you may want to make:
If you are using an older version of Windows like XP, you may not have the CHOICE command. In that case, use ping to simulate sleeping: PING 1.1.1.1 -n 1 -w 60000 >NUL
You can add a line to delete the file after it's printed: DEL /Q %FILENAME%
EDIT (Below): Added multi-file, move and delete capability
set SECONDS=20
set FILEFOLDER=C:\dropfolder
set TEMPFOLDER=%FILEFOLDER%\TEMPFOLDER
set FILEWILDCARD=*.jpg
if not exist "%FILEFOLDER%" ECHO %FILEFOLDER% NOT FOUND ... CTRL-C TO EXIT && PAUSE
if not exist "%TEMPFOLDER%" ECHO %TEMPFOLDER% NOT FOUND ... CTRL-C TO EXIT && PAUSE
:start
cd "%FILEFOLDER%"
dir /b "%FILEWILDCARD%" > filelist.txt
for %%A in (filelist.txt) do if not %%~zA==0 goto printfiles
choice /C a /T %SECONDS% /D a
goto :start
:printfiles
echo FILE(s) FOUND!
del /q "%TEMPFOLDER%\%FILEWILDCARD%"
move "%FILEWILDCARD%" "%TEMPFOLDER%"
cd "%TEMPFOLDER%"
for %%A in ("%FILEWILDCARD%") do MSPAINT /p "%%A"
goto :start
Run a VB.Net in Background and use a FileSystemWatcher to get events for each change in that folder. Upon receiving an event, check the file / action and print the file using whatever App that can print them. A Batch file will likely not work here.

batch file to return next to last line of text file

I have a file that contains the output of a file compare thats written to a text file:
Comparing files C:\LOGS\old.txt and C:\LOGS\NEW.TXT
***** C:\LOGS\old.txt
***** C:\LOGS\NEW.TXT
folder_thats_different
*****
I need to pull out the next to last line "folder_thats_different" and put in a new string:
folder contains a file that is different: folder_thats_different
Yes, I know I can use another language, but I'm stuck with batch files for now.
You can try to read it with a for-loop and take the current line, and always save the previous line
#echo off
setlocal EnableDelayedExpansion
for /f "delims=" %%x in (myFile.txt) do (
set "previous=!last!"
set "last=%%x"
)
echo !previous!
Here's an example you can use as a starting point. Just change the filename in the set command= line to the appropriate name (or replace the command with whatever will gerneate the log listing).
#echo off
#setlocal
(set command=type test.txt)
for /f "usebackq tokens=*" %%i in (`%command%`) do call :process_line %%i
echo next to last line: %old_line%
goto :eof
:process_line
(set old_line=%new_line%)
(set new_line=%*)
goto :eof
Of course, you'll probably want to do something other than simply echoing the found line.
The first answer works for me. I also added 2 lines after the end to allow it to repeat so I could watch an active log file without having to close and reopen it. I do a lot of debugging for the mods that are used in the game Space Engineers.
My version looks like this:
#echo off
setlocal EnableDelayedExpansion
for /f "delims=" %%x in (SpaceEngineers.log) do (
set "previous=!last!"
set "last=%%x"
)
echo !previous!
timeout 15 /nobreak
se_log
The line below stops the batch file from looping too fast and stop the key bypass. To change the amount of time in seconds just change the number "15" to anything you want. To stop the batch file just press ctrl+c.
timeout 15 /nobreak
The line below is the name of the batch file I made so it will tell CMD to run this again.
se_log

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