Jordan
Jordan

Reputation:

Batch script to check when the newest file in a directory was created/modified

I'm quite the novice scripter so please forgive me. I need to create a windows batch script that accomplishes the following:

I will be running this via task scheduler. Any help would be greatly appreciated. Thank you!

Upvotes: 1

Views: 6931

Answers (3)

dolmen
dolmen

Reputation: 8696

This command lists the files ordered by modification time. The latest one is the last one.

> dir /Od /B

This command runs the previous one and store the last file in variable FILE

> for /F "usebackq" %f in (`dir /Od /B`) do set "FILE=%f"

This command shows file information for a specific file:

> dir /N "%FILE%" | findstr /B "[0-9]"

This command will run the previous command, and parse it. The order of fields (year, month, day...) and the delimiters (/ for date, : for hour in my case) is dependent on your regional settings.

> for /f "usebackq tokens=1-5 eol=\  delims=/:\ " %i in (`dir /N "%FILE%" ^| findstr /B "[0-9]"`) do echo [%i%j%k] [%l%m]

We can store the result in variables:

> for /f "usebackq tokens=1-5 eol=\  delims=/:\ " %i in (`dir /N "%FILE%" ^| findstr /B "[0-9]"`) do set DD=%i&set MM=%j&set YYYY=%k&set HH=%l&set MI=%m

Those commands show the current date and time:

> date /t
> time /t

Those commands run, parse and stores into variables:

> for /F "usebackq tokens=1-3 delims=%DATE_DELIM%" %i in (`date /t`) do set DD=%i&set MM=%j&set YYYY=%k
> for /F "usebackq tokens=1,2 delims=%TIME_DELIM%" %i in (`time /t`) do set HH=%i&set MI=%j

That was the easy part. We now have to do some arithmetics to compare the dates. set /A can do arithmetics, but will interpret "08" as octal. So we have to convert values to decimal by removing the leading '0':

> set /A DD=1%DD%-100&set /A MM=1%MM%-100
> set /A HH=1%HH%-100&set /A MI=1%MI%-100

Here is the final script. I had to use a lot of tricks to do date/time arithmetics, and so "24h" is hard coded.

@echo off
setlocal
set DIR=%~f1
set DATE_DELIM=/
set TIME_DELIM=:
for /F "usebackq" %%f in (`dir /Od /B "%DIR%"`) do set "FILE=%%f"

for /F "usebackq tokens=1-5 eol=\  delims=%DATE_DELIM%%TIME_DELIM%\ " %%i in (`dir /N "%FILE%" ^| findstr /B "[0-9]"`) do set A_DD=%%i&set A_MM=%%j&set A_YYYY=%%k&set A_HH=%%l&set A_MI=%%m
set A_DATE=%A_YYYY%%A_MM%%A_DD%
set /A A_DD=1%A_DD%-100&set /A A_MM=1%A_MM%-100
set /A A_TIME=(1%A_HH%-100)*60+%A_MI%-100

for /F "usebackq tokens=1-3 delims=%DATE_DELIM%\ " %%i in (`date /t`) do set B_DD=%%i&set B_MM=%%j&set B_YYYY=%%k
for /F "usebackq tokens=1,2 delims=%TIME_DELIM%\ " %%i in (`time /t`) do set B_HH=%%i&set B_MI=%%j
set B_DATE=%B_YYYY%%B_MM%%B_DD%
set /A B_DD=1%B_DD%-100&set /A B_MM=1%B_MM%-100
set /A B_TIME=(1%B_HH%-100)*60+%B_MI%-100

echo %A_DATE% %A_TIME% - %A_YYYY% %A_MM% %A_DD%
echo %B_DATE% %B_TIME% - %B_YYYY% %B_MM% %B_DD%

:: Check that the file is newer than 24 hours
:: This will not work at daylight change
:: This is probably full of bugs as I had no time to test all cases

if %A_DATE% GEQ %B_DATE% goto :NewFile

:: Past day
:: Whatever the day, if the time of the day is <, this is old
if %A_HH%%A_MI% LSS %B_HH%%B_MI% goto :OldFile

if not %B_MM%==1 goto :WhateverMonth

if %A_DATE:~1,6% EQU %B_DATE:~1,6% goto :SameMonth
:: Change Month
set /A D=%B_YYYY%*12+%B_MM%-%A_YYYY%*12+%A_MM%
if not %D%==-1 goto :OldFile
:LastMonth
:: Is A the last day of the month => yesterday ?
if %A_DD% EQU 2 goto :February
:: 31 is of course the last day
if %A_DD% EQU 31 goto :NewFile
if %A_DD% LSS 30 goto :OldFile

:: Months of 30 days
if %A_DD%==4 goto :NewFile
if %A_DD%==6 goto :NewFile
if %A_DD%==9 goto :NewFile
if %A_DD%==11 goto :NewFile
:: Day is 30 and month has 31 days
goto :OldFile

:February
set /A D=28+!(%A_YYYY% ^% 4)
if %A_DD%==%D% goto :NewFile
:: We do not have to handle others bissextile case which will happen in about
:: 389 years
goto :OldFile

:WhateverMonth
if %A_YYYY%%A_MM% EQU %B_YYYY%%B_MM% goto :SameMonth
goto :OldFile

:SameMonth
set /A D=100+%B_DD%-%A_DD%
if %D% GTR 101 goto :OldFile
:Yesterday
if %B_DD% GTR 1 goto :ChkTime

:ChkTime

:OldFile
echo %FILE% is old.
goto :End

:NewFile
echo %FILE% is new.
goto :End

:End
endlocal

To run it:

> CheckFile.cmd <directory>

This was just to show you that it is possible. But I would not recommend to put it in production before extensive testing. And it is hard to maintain. So instead of batch I recommend to use JScript in the WSH environment or PowerShell.

Upvotes: 1

CGA
CGA

Reputation: 111

You should be able to accomplish this with Forefiles

Upvotes: 1

Drooling_Sheep
Drooling_Sheep

Reputation: 322

ls -t lists the files sorted by modification time. You can grab the first one from its output as the most recently modified.

Upvotes: 0

Related Questions