Link to home
Start Free TrialLog in
Avatar of Pete Long
Pete LongFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Simple to somebody

Right this is probably very easy

I have a directory called C:\directory

I need a chunk of batch file (to tag on the end of a working batchfile)

That deletes every folder in this directory (AND that folders contents) IF the folder is greater than 7 days old. Needs to work on W2K and XP
If you can also explain whats its doing (for my personal education) I'd be gratefull.

Pete (going offline for a while back later)
Avatar of mrdtn
mrdtn

Here you go.  Remove the echo statement in the rmdir command when youo feel comfortable.  Change "root_dir" and "age_limit" to fit your needs.

--

mrdtn

--

@echo off

setlocal enabledelayedexpansion
set root_dir=x:\Directory
set /a age_limit=7
set today=%date%
for /f "tokens=2" %%f in ("%today%") do (
      for /f "tokens=1-3,* delims=/" %%g in ("%%f") do (
            set /a today_year=%%i
            set /a today_month=%%g
            set /a today_day=%%h
      )
)
set /a today_absolute=(%today_year%-1900)*365
set /a today_absolute-=(%today_year%-1901)/100
set /a today_absolute+=(%today_year%-1601)/400
if %today_month% gtr 1 set /a today_absolute+=31
if %today_month% gtr 2 set /a today_absolute+=28
if %today_month% gtr 3 set /a today_absolute+=31
if %today_month% gtr 4 set /a today_absolute+=30
if %today_month% gtr 5 set /a today_absolute+=31
if %today_month% gtr 6 set /a today_absolute+=30
if %today_month% gtr 7 set /a today_absolute+=31
if %today_month% gtr 8 set /a today_absolute+=31
if %today_month% gtr 9 set /a today_absolute+=30
if %today_month% gtr 10 set /a today_absolute+=31
if %today_month% gtr 11 set /a today_absolute+=30
set /a today_absolute+=%today_day%

pushd
cd /d %root_dir%
for /f %%d in ('dir /a:d /b') do (
      set folder_date=%%~td
      for /f "tokens=1" %%f in ("!folder_date!") do (
            for /f "tokens=1-3,* delims=/" %%g in ("%%f") do (
                  set /a folder_year=%%i
                  set /a folder_month=%%g
                  set /a folder_day=%%h
                  set /a folder_absolute=!folder_year!-1900
                  set /a folder_absolute*=365
                  set /a leap_days=!folder_year!-1901
                  set /a leap_days/=100
                  set /a folder_absolute-=!leap_days!
                  set /a leap_days=!folder_year!-1601
                  set /a leap_days/=400
                  set /a folder_absolute+=!leap_days!
                  if !folder_month! gtr 1 set /a folder_absolute+=31
                  if !folder_month! gtr 2 set /a folder_absolute+=28
                  if !folder_month! gtr 3 set /a folder_absolute+=31
                  if !folder_month! gtr 4 set /a folder_absolute+=30
                  if !folder_month! gtr 5 set /a folder_absolute+=31
                  if !folder_month! gtr 6 set /a folder_absolute+=30
                  if !folder_month! gtr 7 set /a folder_absolute+=31
                  if !folder_month! gtr 8 set /a folder_absolute+=31
                  if !folder_month! gtr 9 set /a folder_absolute+=30
                  if !folder_month! gtr 10 set /a folder_absolute+=31
                  if !folder_month! gtr 11 set /a folder_absolute+=30
                  set /a folder_absolute+=!folder_day!
                  set /a folder_age=%today_absolute%-!folder_absolute!
                  echo Folder %%d is !folder_age! days old.
                  if !folder_age! gtr %age_limit% echo rmdir /s /q %%d
            )
      )
)
popd

pause
1)  I did not do a check for folder age inclusive of time of day.  I figured that likely was not necessary -- and as you can image it would be a bit more work.  It can be accomplished however.

2)  The script assumes:
-   the date format returned by the "echo %date%" command is "Fri mm/dd/yyyy" and similarly
-   the folder date/time string being in the format "mm/dd/yyyy hh:mm"

If the format where you are is different, this is a simple change to the order of the %%g, %%h, and %%i.

--

Now for a bit about what it's doing.

The setlocal enabledelayed expansion allows for run-time evaluation of certain variables which are within the for loops, as designated by the use of "!"'s instead of "%"'s.

For each date encountered, it is converted to an absulte number of days since 01/01/1900.  Leap days are accounted for using the divisions by 100 and 400.  These are added and subtracted from the running total accordingly.  Finally the days in ellapsed months are tacked on to the running total (NOTE that only 28 days are included regardless for February -- this is because leapdays have already been accounted for).  Finally the day of month is added on for aa final absolute total.

Jumping ahead, notice the less "pretty" handling of leapdays in the for loops.  This is because of the confusion of perentheses between the statements and the for loop blocks (not entirely sure why, but sometimes you just accept certain behaviors).

Now for the for-loop guts of the script.  Basically, the script goes to the root directory and does a bare directory of folders only (/a:d specifies files with "directory" attributes).  For each folder listed (%%d), the date/time string for the file is assigned to a variable which will be parsed accordingly in the nested loops.  The first nested loop seperates the date string from the time string using the default delimeter of “whitespace” by not specifying the “delims” parameter.  The innermost loop parses the date string and performs the absolute day calculation.  Finally within the innermost loop, the folder date is subtracted fom the current date calculated at the beginning of the file to obtain an age for the folder (not taking into account time-of-day).  If the age exceeds the limit specified at the top of the script, it will be expunged (with extreme prejudice) using the “rmdir /s /q” command.

--


Hope this is helpful / useful.  Let me know if you have any questions.

mrdtn
Avatar of sirbounty
Only thing I would add, since you said it needs to be run under both xp and 2k...

Assign your date to mm/dd/yyyy in both environments with this:

if [%date:~3,0%]==[] set date=%date:~4%

So, if the date variable is 04/16/2004, this line will be skipped, but if it's
Fri 04/16/2004, this will check for the presence of the {space} between Fri and 04 and then reset the date variable to begin at character #4 (cardinally).
Avatar of Pete Long

ASKER

OK guys thanks for the input (and explanations) :)

I do indeed need to run in both enviroments and as you can see https://www.experts-exchange.com/questions/20874254/500-points-fast-Need-this-looking-at.html
i dont have much luck in that department, sheesh didnt think that it would be as complex a deal as it appears to be :(

ok given the above SB's code seems like the way forward in that department, but Ive not got a clue how to splice that into mrdtn's code :( (Im a network engineer guys LOL)

Pete
See his

set today=%date%

Just after that add this line - should do it for ya... ;)

if [%today:~3,0%]==[] set today=%today:~4%

The other option is to replace those lines with:

set today=%date%
for /f "tokens=1,*" %%e in ("%today%") do (
      if not .%%f == . set today=%%f
      for /f "tokens=1-3,* delims=/" %%g in ("!today!") do (
            set /a today_year=%%i
            set /a today_month=%%g
            set /a today_day=%%h
      )
)

--

mrdtn

This basically checks for the second token and uses it if it exists.

Sorry, I didn't have a 2000 machine to test on.  It has been tested on XP.

Also, is your date format mm/dd/yyyy?  If so, there should be no other changes necessary.

SB - Thanks for pointing out the oversight.

--

mrdtn
Actually, I'm not sure SB's suggestion actually will work verbatim.  See, in my original post, I assumed there to be 2 tokens which is why I had the line:

for /f "tokens=2" %%f in ("%today%") do (
 . . .

to extract the second one.

The if [%today:~3,0%]==[] set today=%today:~4% would work if I modified the for loop to get token 1 only or took the loop out altogether -- which would mean changing the %%g in the contained loop.

Not to diminish what SB pointed out and suggested as a solution, but it also needs the other modification.

If you want my modified solution to cut and paste, here it is (mrdtn):

@echo off

setlocal enabledelayedexpansion
set root_dir=x:\Directory
set /a age_limit=7
set today=%date%
for /f "tokens=1,*" %%e in ("%today%") do (
      if not .%%f == . set today=%%f
      for /f "tokens=1-3,* delims=/" %%g in ("!today!") do (
            set /a today_year=%%i
            set /a today_month=%%g
            set /a today_day=%%h
      )
)
set /a today_absolute=(%today_year%-1900)*365
set /a today_absolute-=(%today_year%-1901)/100
set /a today_absolute+=(%today_year%-1601)/400
if %today_month% gtr 1 set /a today_absolute+=31
if %today_month% gtr 2 set /a today_absolute+=28
if %today_month% gtr 3 set /a today_absolute+=31
if %today_month% gtr 4 set /a today_absolute+=30
if %today_month% gtr 5 set /a today_absolute+=31
if %today_month% gtr 6 set /a today_absolute+=30
if %today_month% gtr 7 set /a today_absolute+=31
if %today_month% gtr 8 set /a today_absolute+=31
if %today_month% gtr 9 set /a today_absolute+=30
if %today_month% gtr 10 set /a today_absolute+=31
if %today_month% gtr 11 set /a today_absolute+=30
set /a today_absolute+=%today_day%

pushd
cd /d %root_dir%
for /f %%d in ('dir /a:d /b') do (
      set folder_date=%%~td
      for /f "tokens=1" %%f in ("!folder_date!") do (
            for /f "tokens=1-3,* delims=/" %%g in ("%%f") do (
                  set /a folder_year=%%i
                  set /a folder_month=%%g
                  set /a folder_day=%%h
                  set /a folder_absolute=!folder_year!-1900
                  set /a folder_absolute*=365
                  set /a leap_days=!folder_year!-1901
                  set /a leap_days/=100
                  set /a folder_absolute-=!leap_days!
                  set /a leap_days=!folder_year!-1601
                  set /a leap_days/=400
                  set /a folder_absolute+=!leap_days!
                  if !folder_month! gtr 1 set /a folder_absolute+=31
                  if !folder_month! gtr 2 set /a folder_absolute+=28
                  if !folder_month! gtr 3 set /a folder_absolute+=31
                  if !folder_month! gtr 4 set /a folder_absolute+=30
                  if !folder_month! gtr 5 set /a folder_absolute+=31
                  if !folder_month! gtr 6 set /a folder_absolute+=30
                  if !folder_month! gtr 7 set /a folder_absolute+=31
                  if !folder_month! gtr 8 set /a folder_absolute+=31
                  if !folder_month! gtr 9 set /a folder_absolute+=30
                  if !folder_month! gtr 10 set /a folder_absolute+=31
                  if !folder_month! gtr 11 set /a folder_absolute+=30
                  set /a folder_absolute+=!folder_day!
                  set /a folder_age=%today_absolute%-!folder_absolute!
                  echo Folder %%d is !folder_age! days old.
                  if !folder_age! gtr %age_limit% echo rmdir /s /q %%d
            )
      )
)
popd

pause

ThanQ

from the link i posted above you will see that ive had trouble porting dates from 2K to XP before so forgive my trepidation it would seem the 2K likes to add the three letter date format to the beginning where as XP does not.

i.e

FOR /f "tokens=2,3,4 delims=/ " %%a in ('date /t') do set MyDir=c:\hrbackup\backup\%%a%%b%%c    <---- works in W2K but NOT in XP
FOR /f "tokens=1-3 delims=/" %%a in ('date /t') do set MyDir=c:\hrbackup\backup\%%a%%b%%c   <---works in XP but NOT W2K

Am I to take it that this code allows for this?? Sorry for being Thick :(

and I appreciate the amount of time your spending on this

Pete

Yes:

Here's a simple test script you can run to simulate both cases (without having access to both platforms):

@echo off
setlocal enabledelayedexpansion

echo.
echo testing WinXP environment:

set today=Fri 04/16/2004
for /f "tokens=1,*" %%e in ("%today%") do (
      if not .%%f == . set today=%%f
      for /f "tokens=1-3,* delims=/" %%g in ("!today!") do (
            set /a today_year=%%i
            set /a today_month=%%g
            set /a today_day=%%h
      )
)
echo Year is %today_year%
echo Month is %today_month%
echo Day is %today_day%

echo.
echo testing Win2k environment:

set today=04/16/2004
for /f "tokens=1,*" %%e in ("%today%") do (
      if not .%%f == . set today=%%f
      for /f "tokens=1-3,* delims=/" %%g in ("!today!") do (
            set /a today_year=%%i
            set /a today_month=%%g
            set /a today_day=%%h
      )
)
echo Year is %today_year%
echo Month is %today_month%
echo Day is %today_day%

pause
One more important thing that I want to emphasize.

My date format is MM/DD/YYYY, whereas from you previous post, it appears you have DD/MM/YYYY.  If this is the case, you need to swap the %%g and the %%h where they occur in the set statements (both for "today" and "folder"), such that the loops look like:

      for /f "tokens=1-3,* delims=/" %%g in ("!today!") do (
            set /a today_year=%%i
            set /a today_month=%%h
            set /a today_day=%%g
      )

and

         for /f "tokens=1-3,* delims=/" %%g in ("%%f") do (
              set /a folder_year=%%i
              set /a folder_month=%%h
              set /a folder_day=%%g
              set /a folder_absolute=!folder_year!-1900
              . . .

--

I don't know of a way for the OS to return its specific format in order to do this programatically.

mrdtn
mrdtn

Truely outstanding, I cant test it with the script Im bolting it into till monday.
The test script above runs and returns perfectly in XP.

Ill run it on some test data in 2K and XP on monday, and report back :)

Regards
Pete
>>My date format is MM/DD/YYYY, whereas from you previous post, it appears you have DD/MM/YYYY

sorry thats me clouding the issue, that was for creating folderNAMES with a DD/MM/YYYY format
your script is unconcerned with foldernames and is working on folder AGE (I hope)

Pete
Correct.  I am concerned only with the age of the folder.

However, in computing the absolute dates, the months and day-of-month must be interpreted properly.  Consider the difference in day number within a given year between 1/12 and 12/1.  One is 12 and the other 335 (non leap-year).  So, which-is-which is necessary in that determination.

--

mrdtn
I understand :) most of my scripting is concerened with quick and dirty code, I wouldnt even know where to start producing anything like the above :( Which is why Im glad Ive got free PS membership so I can talk to you guys.

in fact this is what Im using the code for, I have a lot of scripts for backing things up and I want to be able to tag code on the end of the scripts to clean out the old info, It may have been easier to code, the parsing of the foldername (as I date stamp them) but I prefer code that I can pull out and reuse for other things :)

Pete
Thanks.  

Since this is something you wish to tag onto the end of other scripts, I have included a "callable" version of the script below.  From the command line, you would invoke it as:

scriptname c:\Directory" 7

where scriptname is whatever you name it.

From within another batch script, you would invoke it with a CALL statement,

call c:\scriptdir\scriptname "c:\Directory" 7

That should minimize the cutting and pasting you have to do!!

The script cann be placed in a directory which is in the PATH or explicitly called using its full path as shown in the second example (showing scriptdir).

Note the quotes around the root path in each case are only required if there are spaces in the path name.

--

mrdtn
Callable version of script:

@echo off

:init
      if .%2==. goto :usage
      setlocal enabledelayedexpansion
      set root_dir=%1
      set /a age_limit=%2

:gettoday
      set today=%date%
      for /f "tokens=1,*" %%e in ("%today%") do (
            if not .%%f == . set today=%%f
            for /f "tokens=1-3,* delims=/" %%g in ("!today!") do (
                  set /a today_year=%%i
                  set /a today_month=%%g
                  set /a today_day=%%h
            )
      )
      set /a today_absolute=(%today_year%-1900)*365
      set /a today_absolute-=(%today_year%-1901)/100
      set /a today_absolute+=(%today_year%-1601)/400
      if %today_month% gtr 1 set /a today_absolute+=31
      if %today_month% gtr 2 set /a today_absolute+=28
      if %today_month% gtr 3 set /a today_absolute+=31
      if %today_month% gtr 4 set /a today_absolute+=30
      if %today_month% gtr 5 set /a today_absolute+=31
      if %today_month% gtr 6 set /a today_absolute+=30
      if %today_month% gtr 7 set /a today_absolute+=31
      if %today_month% gtr 8 set /a today_absolute+=31
      if %today_month% gtr 9 set /a today_absolute+=30
      if %today_month% gtr 10 set /a today_absolute+=31
      if %today_month% gtr 11 set /a today_absolute+=30
      set /a today_absolute+=%today_day%

:gotoit
      pushd
      cd /d %root_dir%
      for /f %%d in ('dir /a:d /b') do (
            set folder_date=%%~td
            for /f "tokens=1" %%f in ("!folder_date!") do (
                  for /f "tokens=1-3,* delims=/" %%g in ("%%f") do (
                        set /a folder_year=%%i
                        set /a folder_month=%%g
                        set /a folder_day=%%h
                        set /a folder_absolute=!folder_year!-1900
                        set /a folder_absolute*=365
                        set /a leap_days=!folder_year!-1901
                        set /a leap_days/=100
                        set /a folder_absolute-=!leap_days!
                        set /a leap_days=!folder_year!-1601
                        set /a leap_days/=400
                        set /a folder_absolute+=!leap_days!
                        if !folder_month! gtr 1 set /a folder_absolute+=31
                        if !folder_month! gtr 2 set /a folder_absolute+=28
                        if !folder_month! gtr 3 set /a folder_absolute+=31
                        if !folder_month! gtr 4 set /a folder_absolute+=30
                        if !folder_month! gtr 5 set /a folder_absolute+=31
                        if !folder_month! gtr 6 set /a folder_absolute+=30
                        if !folder_month! gtr 7 set /a folder_absolute+=31
                        if !folder_month! gtr 8 set /a folder_absolute+=31
                        if !folder_month! gtr 9 set /a folder_absolute+=30
                        if !folder_month! gtr 10 set /a folder_absolute+=31
                        if !folder_month! gtr 11 set /a folder_absolute+=30
                        set /a folder_absolute+=!folder_day!
                        set /a folder_age=%today_absolute%-!folder_absolute!
                        echo Folder %%d is !folder_age! days old.
                        if !folder_age! gtr %age_limit% echo rmdir /s /q %%d
                  )
            )
      )
      popd
      goto :end

:usage
      echo Usage: %0 [Root Path] [Age Limit in Days]
      goto :end

:end
      pause
      :goto :eof
Here is a cleaned-up version of the working "call-able" script.  I had noticed a small oversight in the leapyear calculation (which actually would not have affected you since your application deals with deltas on the order of days.  Nevertheless, it prompted me to encapsulate what I provided for you earlier and consolidate the day computing routine into a subroutine so the overall script looked nicer.  You will find it much easier to follow now.  In case you are wondering what's going on with the leapyear stuff.  It really has little impact when dealing with relative dates, however, because my approach was to use an epoch of 1900, Jan 01, and compute absolute ellapsed dates from the epoch, I naturally need to be accurate when it comes to leapyears.  This may be more than you wish to know, so skip it if you like.  Anyway . . .

Mathematically, a Y is a leapyear if the following is TRUE:

Y/4 AND !( Y/100 AND !(Y/400) )

where "!" is a logical NOT and by "M/N" I mean that M is evenly divisible by N (i.e. M mod N = 0).

Now thinking in terms of sets, The set of all Y/400 is a subset of the set of all Y/100 which is in turn a subset of all Y/4.  This is where my approach to determining total number of ellapsed leapdays comes from. Basically, initially all modulo 4 years are accumulated, then all modulo 100 years are excluded, then all modulo 400 numbers are RE-INCLUDED (since they would have been excluded in the previous modulo 100 step).

Some fine points of detail:

Leapday increments/decrements use 1901 and 1601 as offsets because these accumulations represent accumulations up to but NOT including the current year.  The 1601 is the most recent modulo 400 year which encompasses all pratical computer generated dates (the next one of which would be 2000, but since we have file dated earlier than 2000, it would not be an appropriate choice).

As a final process in dealing with the leapyear, the current year is considered.  If it is a leap year and the month is March or later , then an extra day is added.

--


@echo off

:init
      if .%2==. goto :usage
      setlocal enabledelayedexpansion
      set root_dir=%1
      set /a age_limit=%2

:gettoday
      set today=%date%
      for /f "tokens=1,*" %%e in ("%today%") do (
            if not .%%f == . set today=%%f
            for /f "tokens=1-3,* delims=/" %%g in ("!today!") do (
                  set /a today_year=%%i
                  set /a today_month=%%g
                  set /a today_day=%%h
            )
      )
      call :compdays %today_year% %today_month% %today_day% today_absolute

:gotoit
      pushd
      cd /d %root_dir%
      for /f %%d in ('dir /a:d /b') do (
            set folder_date=%%~td
            for /f "tokens=1" %%f in ("!folder_date!") do (
                  for /f "tokens=1-3,* delims=/" %%g in ("%%f") do (
                        set /a folder_year=%%i
                        set /a folder_month=%%g
                        set /a folder_day=%%h
                        call :compdays !folder_year! !folder_month! !folder_day! folder_absolute
                        set /a folder_age=%today_absolute%-!folder_absolute!
                        echo Folder %%d is !folder_age! days old.
                        if !folder_age! gtr %age_limit% echo rmdir /s /q %%d
                  )
            )
      )
      popd
      goto :end

:usage
      echo Usage: %0 [Root Path] [Age Limit in Days]
      goto :end

:end
      pause
      goto :eof

:compdays
      :
      : Input  arguments: %1=year %2=month %3=day
      : Return arguments: %4=variable name to receive ellapsed number of days
      :
      set year=%1 & set month=%2 & set day=%3
      :
      : == Start by accruing all the days for past years ==
      :
      set /a ellapsed_days=(%year%-1900)*365
      :
      : == Add in days from ellapsed months ==
      :
      for %%m in (1 3 5 7 8 10)       do if %month% gtr %%m set /a ellapsed_days+=31
      for %%m in (4 6 9 11)             do if %month% gtr %%m set /a ellapsed_days+=30
      for %%m in (2)                   do if %month% gtr %%m set /a ellapsed_days+=28
      :
      : == Leap year compensation ==
      :
      set /a ellapsed_days+=(%year%-1901)/4
      set /a ellapsed_days-=(%year%-1901)/100
      set /a ellapsed_days+=(%year%-1601)/400
      set current_leap=FALSE
      set /a temp=%year%%%4 && if %temp% == 0 set current_leap=TRUE
      set /a temp=%year%%%100 && if %temp% == 0 set current_leap=FALSE
      set /a temp=%year%%%400 && if %temp% == 0 set current_leap=TRUE
      if %current_leap%==TRUE if %month% gtr 2 set /a ellapsed_days+=1
      :
      : == Last but not least, add in the day of the current month ==
      :
      set /a ellapsed_days+=%day%
      :
      set /a %4=%ellapsed_days%
      :
      goto :eof
You have here a perl version...if you don't mind installing the free and powerful perl program :)
https://www.experts-exchange.com/questions/20947290/Delete-All-Contents-of-Folder-Older-than-7-Days.html 
OK mrtdn

Ive ran it on XP, on some test data in the c:\test directory
________________________________________
@echo off

setlocal enabledelayedexpansion
set root_dir=c:\test
set /a age_limit=7
_______________________________________

And it thinks every OLD file is 3 days old?

result
-----------------------------------------------------------------------------
Folder leaveme is 0 days old.
Invalid number.  Numeric constants are either decimal (17),
hexadecimal (0x11), or octal (021).
Folder Malcolm is 3 days old.
Folder Photoshop is 3 days old.
Press any key to continue . . .
----------------------------------------------------------------------------

folder malcolm  created 09 Jan 2004
folder photoshop 20 jan 2004
Dont know what the invalid octal error is telling me :(

Pete
Sorry Pete, I was out of town.  I have reproduced the problem.  Seems I forgot to deal with octal.  In DOS, any number specified with a leading zero is interpreted as an octal digit.  The "09" in one of your folders triggered the error since 9 is not valid octal.  Try the attached solution.  It should take care of the problem.  Basically, I removed the "/a" from the day and month set statements in the main block and added quick checks in the COMPDAYS section.

--

mrdtn

--

@echo off

:init
      if .%2==. goto :usage
      setlocal enabledelayedexpansion
      set root_dir=%1
      set /a age_limit=%2

:gettoday
      set today=%date%
      for /f "tokens=1,*" %%e in ("%today%") do (
            if not .%%f == . set today=%%f
            for /f "tokens=1-3,* delims=/" %%g in ("!today!") do (
                  set /a today_year=%%i
                  set today_month=%%g
                  set today_day=%%h
            )
      )
      call :compdays %today_year% %today_month% %today_day% today_absolute

:gotoit
      pushd
      cd /d %root_dir%
      for /f %%d in ('dir /a:d /b') do (
            set folder_date=%%~td
            for /f "tokens=1" %%f in ("!folder_date!") do (
                  for /f "tokens=1-3,* delims=/" %%g in ("%%f") do (
                        set /a folder_year=%%i
                        set folder_month=%%g
                        set folder_day=%%h
                        call :compdays !folder_year! !folder_month! !folder_day! folder_absolute
                        set /a folder_age=%today_absolute%-!folder_absolute!
                        echo Folder %%d is !folder_age! days old.
                        if !folder_age! gtr %age_limit% echo rmdir /s /q %%d
                  )
            )
      )
      popd
      goto :end

:usage
      echo Usage: %0 [Root Path] [Age Limit in Days]
      goto :end

:end
      pause
      goto :eof

:compdays
      :
      : Input  arguments: %1=year %2=month %3=day
      : Return arguments: %4=variable name to receive ellapsed number of days
      :
      set year=%1 & set month=%2 & set day=%3
      :
      : == Check for leading zeros
      :
      if .%month:~0,1%==.0 set month=%month:~1,1%
      if .%day:~0,1%==.0 set day=%day:~1,1%
      :
      : == Start by accruing all the days for past years ==
      :
      set /a ellapsed_days=(%year%-1900)*365
      :
      : == Add in days from ellapsed months ==
      :
      for %%m in (1 3 5 7 8 10)       do if %month% gtr %%m set /a ellapsed_days+=31
      for %%m in (4 6 9 11)             do if %month% gtr %%m set /a ellapsed_days+=30
      for %%m in (2)                   do if %month% gtr %%m set /a ellapsed_days+=28
      :
      : == Leap year compensation ==
      :
      set /a ellapsed_days+=(%year%-1901)/4
      set /a ellapsed_days-=(%year%-1901)/100
      set /a ellapsed_days+=(%year%-1601)/400
      set current_leap=FALSE
      set /a temp=%year%%%4 && if %temp% == 0 set current_leap=TRUE
      set /a temp=%year%%%100 && if %temp% == 0 set current_leap=FALSE
      set /a temp=%year%%%400 && if %temp% == 0 set current_leap=TRUE
      if %current_leap%==TRUE if %month% gtr 2 set /a ellapsed_days+=1
      :
      : == Last but not least, add in the day of the current month ==
      :
      set /a ellapsed_days+=%day%
      :
      set /a %4=%ellapsed_days%
      :
      goto :eof
Also, forgive me if I am stating the obvious, but if you want to get rid of the "Press any key to continue", just remove the "pause" statement in the :end section.

mrdtn
Also, FYI, hexadecimal numbers are preceded with "0x", but in this case we don;t need to worry.
>>Also, forgive me if I am stating the obvious, but if you want to get rid of the "Press any key to continue", just remove the "pause" statement in the :end section.


hehe no worries

Right Ive run the call-able script on some data, its running the script (output below) but its not removing anything and its reporting the age wrong, (these folders are date NAMED) script was run today so you can see the difference

-------output----------------

Folder 01042004 is 334 days old.
rmdir /s /q 01042004
Folder 02042004 is 303 days old.
rmdir /s /q 02042004
Folder 05042004 is 214 days old.
rmdir /s /q 05042004
Folder 06042004 is 183 days old.
rmdir /s /q 06042004
Folder 07042004 is 153 days old.
rmdir /s /q 07042004
Folder 08042004 is 122 days old.
rmdir /s /q 08042004
Folder 14042004 is 0 days old.
Folder 15042004 is 0 days old.
Folder 16042004 is 0 days old.
Folder 19042004 is 0 days old.
Folder 20042004 is 0 days old.
Folder 22032004 is 1 days old.
Folder 23022004 is 2 days old.
Folder 24022004 is 2 days old.
Folder 24032004 is 1 days old.
Folder 25022004 is 2 days old.
Folder 25032004 is 1 days old.
Folder 26022004 is 2 days old.
Folder 27022004 is 2 days old.
Folder 29032004 is 1 days old.
Folder 29092003 is 360 days old.
rmdir /s /q 29092003
Folder 30032004 is 1 days old.
Folder 31032004 is 1 days old.
Press any key to continue . . .

--------------end output----------------

Pete
ASKER CERTIFIED SOLUTION
Avatar of mrdtn
mrdtn

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>I put it in so everything could be tested before allowing things to get deleted.

:) Sorry I could have spotted that if i wasnt being so lazy, Ill retry when im in the office tommorow :)

Pete
Ah sweet progress! Your run the callable version on some test data and it runs fine, tested it on live data and again no problems :) ThanQ for the amount of time youve put in here - its very much appreciated, I'll close this one out now

one last thing before I sign off......

I realise the call-able version works because the command that launches it passes in the information the script required e.g foldername and time (in days)
(Im guessing here bear with me), am I correct that these are represented in the script by %1 = directory and %2 = days.

so to manually add it to an existing script, Im also guessing the change is in both the :init and :gettoday sections of the scripts? to make it work?
   
@echo off
 
setlocal enabledelayedexpansion
set root_dir=c:\test directory             <------------------what was = to %1
set /a age_limit=7                            <-------------------what was = to %2
set today=%date%
for /f "tokens=1,*" %%e in ("%today%") do (
     if not .%%f == . set today=%%f
     for /f "tokens=1-3,* delims=/" %%g in ("!today!") do (
          set /a today_year=%%i
          set /a today_month=%%h               <----
          set /a today_day=%%g                   <---L-------------Swappped as per out earlier conv to take into account the DDMMYYYY format
     )
)


Its just your callable script has a lot of subroutines in it that i dont understand. the init section seems to have a "goto :usage in it"  and im unsure what that command does - though it looks like some form of error handling? that would be redundant in a tagged on script - correct me if Im wrong.

if so It looks like it would fail on the :compdays routine as the input arguments are different?- sorry for being thick

Regards

Pete

The callable version in the last post does not need any modification other than to remove the echo.  You are right in the fact that the %1 and %2 represent the passed-in directory and number of days, whereas they were hard-coded in the non-callable script.  Actually, %0 represents the first field in the command which is the name of the file itself (see the use of %0 in the usage section).  

In a script which calls the callable script, you would use a line like:

call scriptname c:\Directory 7

where scriptname.bat or scriptname.cmd is the name of the callcable script file.

Actually, the script really only has one subroutine (COMPDAYS).  I added labels to attempt to make it easier to follow.

The usage section is basically the “HELP” – essentially an error handling section if too few arguments are supplied.  Incidentally, the difference between a label which represents a subroutine versus one which does not is in how you branch to them.  For a subroutine, the “call” is used and the code section must have a “goto :eof” at the end in order to work properly.  A non-subroutine is branched to using a “goto” statement and there are no other requirements.

Anyway, don’t mind the questions.  I hope I have clarified things for you.  If not, please let me know.

--

mrdtn
mrdtn - Thanks for that, I like to know how things work. like I said earlier this is'nt really my field Im just a dabbler at scripting (from logon scripts mainly).

From one Expert to another, your handling of this question has been exceptional, apart from the time you have invested writing it, the time spent explaining it to a "thicko" like me is just as valuable. Hope I get a chance to help you out sometime.

With The Greatest Respect

Pete Long
https://www.experts-exchange.com/M_1135172.html
http://petenetlive.hopto.org/home.htm


I'll agree mrdtn - nice job here...very impressive. :)
Thanks to you both.  Nice to get such comments from two heavy-hitters!

The dependence on date format does bug me -- ESPECIALLY WHEN FILE DELETION IS INVOLVED . . .  so . . . . I have begun to write a subroutine to parse the date based on the "sDateFormat" registry key value.  Then we'll have put the effect of Windows Regional Settings to rest!

I'll post the result later when it's finished.

--

mrdtn
:)
Okay, I couldn't help myself!  Actually, I did this because there are so many date/time related questions in this area -- and I would prefer to put to rest the issue with regional date settings.  Basically, the script below functionally does exactly what the accepted answer does -- BUT independently of the date format for the particular installation of windows.  Looking into this issue, it became very much aware to me that the date format can be just about anything -- based on what one customizes in the regional settings portion oof the control panel.  Therefore, the approach here is to essentially create a PUSH and POP for the date format.  Basically, after querying the registry for the current date format and saving this information, a date format more taylored to computing date-related math is "pushed" into the registry for the duration of the command script.  At script end, the original date format is "popped" back into the registry as if nothing had changed.  No more worrying about MM/DD or DD/MM -- or even potentially WORSE where someone has configured their machine to output date as 24-Apr-2004 -- and even MORE worse when a different language might be involved.  Anyway, my date format of choice is "yyyyMMdd" (and for some reason the M's must be capitalized) -- and therefore all my date parsing can be consistent.

Anyway, the pasted code below is a complete solution to the original question -- with the echo statements still in(!!), however, the three sections (:pushdfmt, :popdfmt, and :datefmt) together can be pasted to any script and used in the same manner.  The extra "goto :eof" before :pushdfmt is there for good measure and should be pasted as well to prevent accidental branching.

Note: the new methods here do involve registry modification (to a relatively minor extent).

Anyway Pete, sorry for cluttering up your inbox.  I wanted to post this for the greater good of the TA.  It seems like every other question has something to do with date/time parsing.

--

mrdtn

--

@echo off

:init
      if .%2==. goto :usage
      setlocal enabledelayedexpansion
      set root_dir=%1
      set /a age_limit=%2
      call :pushdfmt

:gettoday
      set today=%date%
      set today_year=%today:~0,4%
      set today_month=%today:~4,2%
      set today_day=%today:~6,2%
      call :compdays %today_year% %today_month% %today_day% today_absolute

:gotoit
      pushd %root_dir%
      for /f %%d in ('dir /a:d /b') do (
            set folder_date=%%~td
            set /a folder_year=!folder_date:~0,4!
            set folder_month=!folder_date:~4,2!
            set folder_day=!folder_date:~6,2!
            call :compdays !folder_year! !folder_month! !folder_day! folder_absolute
            set /a folder_age=%today_absolute%-!folder_absolute!
            echo Folder %%d is !folder_age! days old.
            if !folder_age! gtr %age_limit% echo rmdir /s /q %%d
      )
      goto :end

:usage
      echo Usage: %0 [Root Path] [Age Limit in Days]
      goto :end

:end
      popd
      call :popdfmt
      goto :eof

:compdays
      :
      : Input  arguments: %1=year %2=month %3=day
      : Return arguments: %4=variable name to receive ellapsed number of days
      :
      set year=%1 & set month=%2 & set day=%3
      :
      : == Check for leading zeros
      :
      set /a year=%year%
      if .%month:~0,1%==.0 set /a month=%month:~1,1%
      if .%day:~0,1%==.0 set /a day=%day:~1,1%
      :
      : == Start by accruing all the days for past years ==
      :
      set /a ellapsed_days=(%year%-1900)*365
      :
      : == Add in days from ellapsed months ==
      :
      for %%m in (1 3 5 7 8 10)       do if %month% gtr %%m set /a ellapsed_days+=31
      for %%m in (4 6 9 11)             do if %month% gtr %%m set /a ellapsed_days+=30
      for %%m in (2)                   do if %month% gtr %%m set /a ellapsed_days+=28
      :
      : == Leap year compensation ==
      :
      set /a ellapsed_days+=(%year%-1901)/4
      set /a ellapsed_days-=(%year%-1901)/100
      set /a ellapsed_days+=(%year%-1601)/400
      set current_leap=FALSE
      set /a temp=%year%%%4 && if %temp% == 0 set current_leap=TRUE
      set /a temp=%year%%%100 && if %temp% == 0 set current_leap=FALSE
      set /a temp=%year%%%400 && if %temp% == 0 set current_leap=TRUE
      if %current_leap%==TRUE if %month% gtr 2 set /a ellapsed_days+=1
      :
      : == Last but not least, add in the day of the current month ==
      :
      set /a ellapsed_days+=%day%
      :
      set /a %4=%ellapsed_days%
      :
      goto :eof

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: PUSHDFMT, POPDFMT package for Windows 2k/XP
::
      goto :eof
:pushdfmt
      call :datefmt push && goto :eof
:popdfmt
      call :datefmt pop && goto :eof
:datefmt
      setlocal enabledelayedexpansion
      set tempfile=%0
      set tempfile=%tempfile::=%
      if "%1"=="push" (
            set reg_key=HKEY_CURRENT_USER\Control Panel\International
            set reg_string=sShortDate
            for %%f in (_%tempfile% __%tempfile%) do (
                  if exist %%f (
                        echo Error creating temporary files.  This script will exit after a key is pressed.
                        pause > nul
                        exit
                  )
            )
            reg export "!reg_key!" _%tempfile% > nul
            type _%tempfile% > __%tempfile%
            set reg_header=
            for /f "tokens=*" %%z in (__%tempfile%) do if "!reg_header!"=="" set reg_header=%%z
            for /f "tokens=3" %%v in ('reg query "!reg_key!" /v !reg_string! ^| find /i "!reg_string!"') do set date_format=%%v
            for %%f in (_%tempfile% __%tempfile%) do (
                  echo !reg_header! > %%f
                  echo [!reg_key!] >> %%f
            )
            >> _%tempfile% echo "!reg_string!"="yyyyMMdd"
            >> __%tempfile% echo "!reg_string!"="!date_format!"
            reg import _%tempfile% > nul
      ) else if "%1"=="pop" (
            reg import __%tempfile% > nul
            for %%f in (_%tempfile% __%tempfile%) do del %%f
            goto :eof
      ) else echo ! - DATAFMT - Bad argument.
      goto :eof
::
::PUSHDFMT, POPDFMT package for Windows 2k/XP
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
mrdtn - if you're interested, cany you give this one a shot: http:Q_20962395.html
mrdtn I'll have a play with this when Im back at work.

>>I wanted to post this for the greater good of the TA

Good Drills, a lot of questions could benefit, from this treatment.

Pete
I must interject here.  Fierst of all this is an excellent batch file and I wish I had the skills to write this way without digging all over the web.

Since I do not I use Jpsoft's excellent 4NT cmd.exe or command.com replacements.  jpsoft.com

To delete folders olver than 7 days it would be a one lines.

del /[d-7,1/1/80]  /foldername /s *.*

that's it and it works perfectly everytime.

Also someonje recommended using FORFILES the NT resource kit utility in another Experts Exchange article.  Is there any reason NOT to use the forfiles method over the one here (assuming you will not buy 4NT or TakeCommand from JPsoft)

FORFILES -pc:\foldername -s -m*.* -d-7 -c"CMD /C del @FILE"

-p = path
-s = include subdirs
-m = match filetype
-d = age in days (can also be set as an absolute date ie DDMMYYYY) note that - or + can be used here
-c = command to execute



Thanks

Doug
dcohn,

Thanks for the comment and the valueable input you have provided, which others searching EE may find beneficial.  My approach was to use only what was built-in . . which can be a strangely entertaining challenge.  I have actually used a modified version of this to perform a recursive procedure which acts differently on directories than it does files . . in esscence, to perform a directory tree secure "file-wipe".  In such a case, the programmability of the CMD language is appreciated.

mrdtn (aka Doug, as well)
the question that keeps on giving :)