Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I compare timestamps of files in a batch script?

In DOS batch files, the method of achieving certain things is somewhat obfuscated. Fortunately, there is a fantastic reference site for batch scripting: Simon Sheppard's SS64. (The same site also has plenty of information about Bash.)

One difficulty is branching execution based on whether a directory is empty. The obvious if exist "%dir%\*.*" doesn't work. But it can be done with this conditional execution trick:

( dir /b /a "%dir%" | findstr . ) > nul && (   echo %dir% non-empty ) || (   echo %dir% empty ) 

Another awkward problem is branching according to file contents. Again that can be done like this:

( fc /B "%file1%" "%file2%" | find "FC: no differences encountered" ) > nul && (   echo "%file1%" and "%file2%" are the same ) || (   echo "%file1%" and "%file2%" are different ) 

So, my question is:
Is there a way to do branch according to the time-stamps of files?

This is the sort of thing I want:

REM *** pseudo-code! if "%file1%" is_newer_than "%file2%" (   echo "%file1%" is newer ) else if "%file1%" is_older_than "%file2%" (   echo "%file2%" is newer ) else (   echo "%file1%" and "%file2%" are the same age ) 

Thanks.

like image 784
Rhubbarb Avatar asked Nov 06 '09 11:11

Rhubbarb


People also ask

How do I timestamp in CMD?

To display timestamp on command prompt, use the special character \D{} for PS1 shell variable. It is possible to display arbitrary time format by putting a special character based on strftime() function into {} . For more information on special characters, refer to the online manual “STRFTIME(3) man 3 strftime. ”

How do you compare two files to see if they are the same?

Probably the easiest way to compare two files is to use the diff command. The output will show you the differences between the two files. The < and > signs indicate whether the extra lines are in the first (<) or second (>) file provided as arguments. In this example, the extra lines are in backup.

What does %% mean in batch script?

Represents a replaceable parameter. Use a single percent sign ( % ) to carry out the for command at the command prompt. Use double percent signs ( %% ) to carry out the for command within a batch file. Variables are case sensitive, and they must be represented with an alphabetical value such as %a, %b, or %c. ( <set> )


2 Answers

You can find the newer of two files with one line of batch script. Just list the files in date order, oldest first, which means the last file listed must be the newer file. So if you save the file name each time, the last name put in your variable will be the newest file.

For, example:

SET FILE1=foo.txt SET FILE2=bar.txt FOR /F %%i IN ('DIR /B /O:D %FILE1% %FILE2%') DO SET NEWEST=%%i ECHO %NEWEST% is (probably) newer. 

This unfortunately doesn't cope with the date stamps being the same. So we just need to check if the files have the same date and time stamp first:

SET FILE1=foo.txt SET FILE2=bar.txt  FOR %%i IN (%FILE1%) DO SET DATE1=%%~ti FOR %%i IN (%FILE2%) DO SET DATE2=%%~ti IF "%DATE1%"=="%DATE2%" ECHO Files have same age && GOTO END  FOR /F %%i IN ('DIR /B /O:D %FILE1% %FILE2%') DO SET NEWEST=%%i ECHO Newer file is %NEWEST%  :END 
like image 80
Dave Webb Avatar answered Sep 16 '22 19:09

Dave Webb


Dave Webb's soution while a great one will of course only work on files in the same directory.

Here is a solution that will work on any two files.

First get the file time (see How to get file's last modified date on Windows command line?).

for %%a in (MyFile1.txt) do set File1Date=%%~ta for %%a in (MyFile2.txt) do set File2Date=%%~ta  

However one has then to manually break the date and time into it's components since Cmd.exe will compare them as a sting thus 2 > 10 and 10:00AM > 2:00PM.

Compare first the years, then the months, then the day, then AM/PM, then the hour, and then the minute and second, (actually time consuming, but I don't have on the minute a better idea), see the final code at the end.

However this solution will not work if the files are in the same minute but different by the second.

If you are to this level of precision then get the filetime by using the "forfiles" command (see https://superuser.com/questions/91287/windows-7-file-properties-date-modified-how-do-you-show-seconds).

for /F "tokens=*" %%a in ('forfiles /m MyFile1.txt /c "cmd /c echo @fdate @ftime"')      do set File1Date=%%a for /F "tokens=*" %%a in ('forfiles /m MyFile2.txt /c "cmd /c echo @fdate @ftime"')      do set File2Date=%%a     

Note that "ForFiles" has a limitation that it can't take a path with spaces, so if you have a path with spaces you will have to change to that directory first, see forfiles - spaces in folder path

Comparison Code

:compareFileTime set "originalFileTime=%1" set "secondFileTime=%2"  for /F "tokens=1,2,3 delims= " %%a in (%originalFileTime%) do (      set "originalDatePart=%%a"       set "originalTimePart=%%b"       set "originalAmPmPart=%%c"   ) for /F "tokens=1,2,3 delims= " %%a in (%secondFileTime%) do (     set "secondDatePart=%%a"     set "secondTimePart=%%b"     set "secondAmPmPart=%%c" ) for /F "tokens=1,2,3 delims=/" %%a in ("%originalDatePart%") do (         set "originalMonthPart=%%a"         set "originalMonthDayPart=%%b"         set "originalYearPart=%%c"          rem We need to ensure that the year is in a 4 digit format and if not we add 2000 to it         rem Cmd considers "50" > "100" but 50 < 100, so don't surround it with qoutes     if %%c LSS 100 set "originalYearPart=20%%c ) for /F "tokens=1,2,3 delims=/" %%a in ("%secondDatePart%") do (     set "secondMonthPart=%%a"     set "secondMonthDayPart=%%b"     set "secondYearPart=%%c"          rem We need to ensure that the year is in a 4 digit format and if not we add 2000 to it     rem Cmd considers "50" > "100" but 50 < 100, so don't surround it with quotes         if %%c LSS 100 set "secondYearPart=20%%c     )  if %originalYearPart% GTR %secondYearPart% goto newer if %originalYearPart% LSS %secondYearPart% goto older  rem We reach here only if the year is identical rem Cmd considers "2" > "10" but 2 < 10, so don't surround it with quotes or you will have to set the width explicitly if %originalMonthPart% GTR %secondMonthPart% goto newer if %originalMonthPart% LSS %secondMonthPart% goto older  if %originalMonthDayPart% GTR %secondMonthDayPart% goto newer if %originalMonthDayPart% LSS %secondMonthDayPart% goto older  rem We reach here only if it is the same date if %originalAmPmPart% GTR %secondAmPmPart% goto newer if %originalAmPmPart% LSS %secondAmPmPart% goto older  rem we reach here only if i=t is the same date, and also the same AM/PM for /F "tokens=1 delims=:" %%a in ("%originalTimePart%") do set "originalHourPart=%%a"  for /F "tokens=1 delims=:" %%a in ("%secondTimePart%") do set "secondHourPart=%%a"  rem Cmd considers "2" > "10" but 2 < 10, so don't surround it with qoutes or you will have to set the width explicitly if %originalHourPart% GTR %secondHourPart% goto newer if %originalHourPart% LSS %secondHourPart% goto older  rem The minutes and seconds can be compared directly if %originalTimePart% GTR %secondTimePart% goto newer if %originalTimePart% LSS %secondTimePart% goto older if %originalTimePart% EQU %secondTimePart% goto same  goto older exit /b  :newer echo "newer" exit /b  :older echo "older" exit /b  :same echo "same" exit /b 
like image 25
yoel halb Avatar answered Sep 17 '22 19:09

yoel halb