Link to home
Start Free TrialLog in
Avatar of W.E.B
W.E.B

asked on

Batch to delete files based on date in File name

Good Day,
I have a folder in (C:\Users\Wassim\Desktop\Delete_Older_Invoices)
Files with date in the file name.
Examples
48-528277.20130515.txt
391-593063.20180216.csv
11582-593463.20170223.txt
1091-593132.20180223.csv
1077-592177.20180209.xls
4025-532154.20130915.xlsx

I'm looking for a batch that can Check the date in the file name and delete files older than x days.
Any help is appreciated.
SOLUTION
Avatar of Qlemo
Qlemo
Flag of Germany image

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
Avatar of Bill Prew
Bill Prew

Here is a BAT approach that should work.  Currently in test mode (no files will be deleted), but run it from a command console and it will display the files it would select for deletion, and their age.  If it looks good, remove the ECHO before the DEL statement and run for real.  As always, test thoroughly.

@echo off
setlocal EnableDelayedExpansion

REM Define base for folder, and days to keep old files
set BaseDir=C:\Users\Wassim\Desktop\Delete_Older_Invoices
set DaysToKeep=30

REM Get current date in YYYYMMDD format, convert to julian
set LocalDateTime=
for /f "tokens=* skip=1" %%A in ('wmic os get LocalDateTime') do (
  if not defined LocalDateTime (
    set LocalDateTime=%%A
    call :jDate jToday !LocalDateTime:~0,8!
  )
)

REM Should never happen, but just be be extra safe
if not defined LocalDateTime exit /b

REM Process all files, delete if too old
for /f "tokens=*" %%A in ('dir /a-d /b "%BaseDir%\*-*.20??????.*"') do (
  set FileName=%%~nA
  call :jDate jFileDate !FileName:~-8!
  set /A FileAge = !jToday! - !jFileDate!
  if !FileAge! GTR %DaysToKeep% (
    echo Removing File:[%BaseDir%\%%~A], Age:[!FileAge! days]
    ECHO del "%BaseDir%\%%~A"
  )
)

REM Done
exit /b

REM Subroutine to calculate julian date from (YYYYMMDD) date
:jDate [return-variable] [date-string]
  set DateStr=%~2
  set yy=%DateStr:~0,4%
  set /A mm=1%DateStr:~4,2%-100
  set /A dd=1%DateStr:~6,2%-100
  set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
  set /a %~1=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
  exit /b

Open in new window


»bp
Bill, of course that works, but isn't it a complicated way to first calculate Julian dates for each file? A string compare with yyyymmdd format of today - x days would work and is much easier to follow ;-).
Avatar of W.E.B

ASKER

Thank you very much guys,
Can we limit this to only the 4 files types I have in the folder?
.txt
,csv
.xls
.xlsx

Thank you,
If those are the only file types in the folder then why "limit" it?


»bp
Avatar of W.E.B

ASKER

I have some other file types in the same folder.
.pdf, .bak, .sql, .doc, .docx,...
Updated BAT to filter extensions.

@echo off
setlocal EnableDelayedExpansion

REM Define base for folder, and days to keep old files
set BaseDir=C:\Users\Wassim\Desktop\Delete_Older_Invoices
set KeepDays=30

REM Get current date in YYYYMMDD format, convert to julian
set LocalDateTime=
for /f "tokens=* skip=1" %%A in ('wmic os get LocalDateTime') do (
  if not defined LocalDateTime (
    set LocalDateTime=%%A
  )
)

REM Should never happen, but just be be extra safe
if not defined LocalDateTime exit /b

REM Convert current date to julian, suptract days to keep, convert cutoff back to YYYYMMDD gregorian
call :jDate jToday %LocalDateTime:~0,8%
set /a jKeepDate=jToday-KeepDays
call :gDate KeepDate %jKeepDate%

REM Process all files, delete if too old
for /f "tokens=*" %%A in ('dir /a-d /b "%BaseDir%\*-*.20??????..txt" "%BaseDir%\*-*.20??????..csv" "%BaseDir%\*-*.20??????..xls" "%BaseDir%\*-*.20??????..xlsx"') do (
  set FileName=%%~nA
  if !FileName:~-8! LSS %KeepDate% (
    echo Removing File:[%BaseDir%\%%~A], Age:[!FileAge! days]
    ECHO del "%BaseDir%\%%~A"
  )
)

REM Done
exit /b

REM Subroutine to calculate julian date from (YYYYMMDD) date
:jDate [return-variable] [date-string]
  set DateStr=%~2
  set yy=%DateStr:~0,4%
  set /A mm=1%DateStr:~4,2%-100
  set /A dd=1%DateStr:~6,2%-100
  set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
  set /a %~1=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
  exit /b

REM Subroutine to calculate gregorian date in (YYYYMMDD) format from julian date
:gDate [return-variable] [date-string]
  set /a L=%~2+68569,N=4*L/146097,L=L-(146097*N+3)/4,I=4000*(L+1)/1461001
  set /a L=L-1461*I/4+31,J=80*L/2447,K=L-2447*J/80,L=J/11
  set /a J=J+2-12*L,I=100*(N-49)+I+L
  set /a YYYY=I,MM=100+J,DD=100+K
  set MM=%MM:~-2%
  set DD=%DD:~-2%
  set %~1=%YYYY%%MM%%DD%
  exit /b

Open in new window


»bp
$age = 30
$folder = 'C:\Temp\EE'

$dt = get-date (get-date).AddDays(-$age) -f 'yyyyMMdd'
get-childitem $folder\* -File |
  ? { $_.Extension -in '.txt', '.csv', '.xls', '.xlsx' } |
  ? { $dtFile = ($_.BaseName -split '\.')[-1]; $dtFile -like '2???????' -and $dtFile -le $dt } |
  Remove-Item -WhatIf

Open in new window

Avatar of W.E.B

ASKER

Good day,
Qlemo, the PowerShell is working fine.

Bill,
The script is not deleting the files. (I did remove the ECHO)     ECHO del "%BaseDir%\%%~A"
Do I need to remove anything else?

Thanks again.
No, that's all.  When you ran it the first time, did it display any files that it would have deleted?


»bp
Avatar of W.E.B

ASKER

Sorry Bill for not replying faster
I ran it form the command line, no files were listed.
Let me do a comprehensive test scenario here...


»bp
I see a/the problem.  In a cut and paste I seem to have gotten double periods before the extensions.  Change this statement:

for /f "tokens=*" %%A in ('dir /a-d /b "%BaseDir%\*-*.20??????..txt" "%BaseDir%\*-*.20??????..csv" "%BaseDir%\*-*.20??????..xls" "%BaseDir%\*-*.20??????..xlsx"') do (

Open in new window

to:

for /f "tokens=*" %%A in ('dir /a-d /b "%BaseDir%\*-*.20??????.txt" "%BaseDir%\*-*.20??????.csv" "%BaseDir%\*-*.20??????.xls" "%BaseDir%\*-*.20??????.xlsx"') do (

Open in new window


»bp
ASKER CERTIFIED SOLUTION
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
Avatar of W.E.B

ASKER

Thank you very much.
Welcome.


»bp
Avatar of W.E.B

ASKER

Hi Bill,
Not sure if I still can ask a question.
I forgot to add one thing, I have a folder inside the directory as well
The batch doesn't seem to delete the files in it.
C:\Users\Wassim\Desktop\Delete_Older_Invoices\Split reports\New Invoices

Much appreciated.
That is correct, the BAT solution doesn't recurse into subfolders.  So the question is do you want to recurse into all subfolders under the first level folders in the base folder, or only this one specific one?  If just this specific one, then can it exist in other folders besides "Split Reports"?

If it is just one isolated other directory you want to clean then you could just add it in the code as follows.  But if it can exist in other locations, or there are other "special case" we might want to change the code differently...

@echo off
setlocal EnableDelayedExpansion

REM Define base for folder, and days to keep old files
set BaseDir=C:\Users\Wassim\Desktop\Delete_Older_Invoices
set BaseDir2=C:\Users\Wassim\Desktop\Delete_Older_Invoices\Split reports\New Invoices
set KeepDays=30

REM Get current date in YYYYMMDD format, convert to julian
set LocalDateTime=
for /f "tokens=* skip=1" %%A in ('wmic os get LocalDateTime') do (
  if not defined LocalDateTime (
    set LocalDateTime=%%A
  )
)

REM Should never happen, but just be be extra safe
if not defined LocalDateTime exit /b

REM Convert current date to julian, suptract days to keep, convert cutoff back to YYYYMMDD gregorian
call :jDate jToday %LocalDateTime:~0,8%
set /a jKeepDate=jToday-KeepDays
call :gDate KeepDate %jKeepDate%

REM Process all files, delete if too old
for /f "tokens=*" %%A in ('dir /a-d /b "%BaseDir%\*-*.20??????.txt" "%BaseDir%\*-*.20??????.csv" "%BaseDir%\*-*.20??????.xls" "%BaseDir%\*-*.20??????.xlsx"') do (
  set FileName=%%~nA
  if !FileName:~-8! LSS %KeepDate% (
    echo Removing File:[%BaseDir%\%%~A], Date:[!FileName:~-8!]
    ECHO del "%BaseDir%\%%~A"
  )
)

REM Process all files, delete if too old
for /f "tokens=*" %%A in ('dir /a-d /b "%BaseDir2%\*-*.20??????.txt" "%BaseDir2%\*-*.20??????.csv" "%BaseDir2%\*-*.20??????.xls" "%BaseDir2%\*-*.20??????.xlsx"') do (
  set FileName=%%~nA
  if !FileName:~-8! LSS %KeepDate% (
    echo Removing File:[%BaseDir%\%%~A], Date:[!FileName:~-8!]
    ECHO del "%BaseDir%\%%~A"
  )
)

REM Done
exit /b

REM Subroutine to calculate julian date from (YYYYMMDD) date
:jDate [return-variable] [date-string]
  set DateStr=%~2
  set yy=%DateStr:~0,4%
  set /A mm=1%DateStr:~4,2%-100
  set /A dd=1%DateStr:~6,2%-100
  set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
  set /a %~1=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
  exit /b

REM Subroutine to calculate gregorian date in (YYYYMMDD) format from julian date
:gDate [return-variable] [date-string]
  set /a L=%~2+68569,N=4*L/146097,L=L-(146097*N+3)/4,I=4000*(L+1)/1461001
  set /a L=L-1461*I/4+31,J=80*L/2447,K=L-2447*J/80,L=J/11
  set /a J=J+2-12*L,I=100*(N-49)+I+L
  set /a YYYY=I,MM=100+J,DD=100+K
  set MM=%MM:~-2%
  set DD=%DD:~-2%
  set %~1=%YYYY%%MM%%DD%
  exit /b

Open in new window


»bp
Avatar of W.E.B

ASKER

Hi Bill,
thank you very much, (it's working great)
I hate to be a pain,
but, what if the file was in the C Drive -- \Export Invoices

I tried to change the base Dir, but not deleting.

set BaseDir=C:\Program Files (x86)\EZSH 3.2
set BaseDir2=C:\Program Files (x86)\EZSH 3.2\CSV Exporter\NEW CSV Exporter\Export Invoices

thank you
Typically you will need to have elevated privs to delete from program files folders, so you would need to launch the BAT file via "run as administrator".


»bp
Avatar of W.E.B

ASKER

I tried to run it as Administrator,
when I try to list the files
I get error
\EZSH was unexpected at this time.

When I try t run the batch, nothing deletes.
when I try to list the files
I get error
\EZSH was unexpected at this time.

Do you mean just from a command line?  If so you need quotes around the path since there are spaces in it, like:

DIR "C:\Program Files (x86)\EZSH 3.2"

Open in new window

(the BAT script always does this so it won't be a problem inside the script)


»bp
Avatar of W.E.B

ASKER

Thanks Bill for your time.
Still not deleting
set BaseDir=C:\Program Files (x86)\EZSH 3.2
set BaseDir2=C:\Program Files (x86)\EZSH 3.2\CSV Exporter\NEW CSV Exporter\Export Invoices
What does this command show at a command line?

dir "C:\Program Files (x86)\EZSH 3.2\*-*.20??????.txt" "C:\Program Files (x86)\EZSH 3.2\*-*.20??????.csv" "C:\Program Files (x86)\EZSH 3.2\*-*.20??????.xls" "C:\Program Files (x86)\EZSH 3.2\*-*.20??????.xlsx"

Open in new window


»bp
Avatar of W.E.B

ASKER

HI Bill
if I run
dir "C:\Program Files (x86)\EZSH 3.2\*-*.20??????.txt" "C:\Program Files (x86)\EZSH 3.2\*-*.20??????.csv" "C:\Program Files (x86)\EZSH 3.2\*-*.20??????.xls" "C:\Program Files (x86)\EZSH 3.2\*-*.20??????.xlsx"

 Directory of C:\Program Files (x86)\EZSH 3.2
File Not Found
Which is correct, I don't have any files

But, if I run this
dir "C:\Program Files (x86)\EZSH 3.2\CSV Exporter\NEW CSV Exporter\Export Invoices\*-*.20??????.txt" "C:\Program Files (x86)\EZSH 3.2\CSV Exporter\NEW CSV Exporter\Export Invoices\*-*.20??????.csv" "C:\Program Files (x86)\EZSH 3.2\CSV Exporter\NEW CSV Exporter\Export Invoices\*-*.20??????.xls" "C:\Program Files (x86)\EZSH 3.2\CSV Exporter\NEW CSV Exporter\Export Invoices\*-*.20??????.xlsx"

It lists all files to be deleted.
Odd.  Okay, I added a little debug ECHO at the top of each file loop in the BAT below.  It should display all files it finds that match the pattern in each folder, regardless of date stamp.  See what this gives...

@echo off
setlocal EnableDelayedExpansion

REM Define base for folder, and days to keep old files
set "BaseDir=C:\Program Files (x86)\EZSH 3.2"
set "BaseDir2=C:\Program Files (x86)\EZSH 3.2\CSV Exporter\NEW CSV Exporter\Export Invoice"
set KeepDays=30

REM Get current date in YYYYMMDD format, convert to julian
set LocalDateTime=
for /f "tokens=* skip=1" %%A in ('wmic os get LocalDateTime') do (
  if not defined LocalDateTime (
    set LocalDateTime=%%A
  )
)

REM Should never happen, but just be be extra safe
if not defined LocalDateTime exit /b

REM Convert current date to julian, suptract days to keep, convert cutoff back to YYYYMMDD gregorian
call :jDate jToday %LocalDateTime:~0,8%
set /a jKeepDate=jToday-KeepDays
call :gDate KeepDate %jKeepDate%

REM Process all files, delete if too old
for /f "tokens=*" %%A in ('dir /a-d /b "%BaseDir%\*-*.20??????.txt" "%BaseDir%\*-*.20??????.csv" "%BaseDir%\*-*.20??????.xls" "%BaseDir%\*-*.20??????.xlsx"') do (
  set FileName=%%~nA
  ECHO Checking file:[%BaseDir%\%%~A], Date:[!FileName:~-8!]
  if !FileName:~-8! LSS %KeepDate% (
    echo Removing File:[%BaseDir%\%%~A], Date:[!FileName:~-8!]
    ECHO del "%BaseDir%\%%~A"
  )
)

REM Process all files, delete if too old
for /f "tokens=*" %%A in ('dir /a-d /b "%BaseDir2%\*-*.20??????.txt" "%BaseDir2%\*-*.20??????.csv" "%BaseDir2%\*-*.20??????.xls" "%BaseDir2%\*-*.20??????.xlsx"') do (
  set FileName=%%~nA
  ECHO Checking file:[%BaseDir2%\%%~A], Date:[!FileName:~-8!]
  if !FileName:~-8! LSS %KeepDate% (
    echo Removing File:[%BaseDir%\%%~A], Date:[!FileName:~-8!]
    ECHO del "%BaseDir%\%%~A"
  )
)

REM Done
exit /b

REM Subroutine to calculate julian date from (YYYYMMDD) date
:jDate [return-variable] [date-string]
  set DateStr=%~2
  set yy=%DateStr:~0,4%
  set /A mm=1%DateStr:~4,2%-100
  set /A dd=1%DateStr:~6,2%-100
  set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
  set /a %~1=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
  exit /b

REM Subroutine to calculate gregorian date in (YYYYMMDD) format from julian date
:gDate [return-variable] [date-string]
  set /a L=%~2+68569,N=4*L/146097,L=L-(146097*N+3)/4,I=4000*(L+1)/1461001
  set /a L=L-1461*I/4+31,J=80*L/2447,K=L-2447*J/80,L=J/11
  set /a J=J+2-12*L,I=100*(N-49)+I+L
  set /a YYYY=I,MM=100+J,DD=100+K
  set MM=%MM:~-2%
  set DD=%DD:~-2%
  set %~1=%YYYY%%MM%%DD%
  exit /b

Open in new window


»bp
Avatar of W.E.B

ASKER

Sorry Bill,
still not deleting the files.
ECHO del "%BaseDir%\%%~A"

I removed the Echo,
Doh, I see it.  When I/we added the BaseDir2 logic, I didn't change all  the BaseDir references to BaseDir2.  Existing code is shown below.  Notice there are still some BaseDir references at the bottom, including the DEL statement.  Change all those to be BaseDir2.

REM Process all files, delete if too old
for /f "tokens=*" %%A in ('dir /a-d /b "%BaseDir2%\*-*.20??????.txt" "%BaseDir2%\*-*.20??????.csv" "%BaseDir2%\*-*.20??????.xls" "%BaseDir2%\*-*.20??????.xlsx"') do (
  set FileName=%%~nA
  ECHO Checking file:[%BaseDir2%\%%~A], Date:[!FileName:~-8!]
  if !FileName:~-8! LSS %KeepDate% (
    echo Removing File:[%BaseDir%\%%~A], Date:[!FileName:~-8!]
    ECHO del "%BaseDir%\%%~A"
  )
)

Open in new window


»bp
Avatar of W.E.B

ASKER

Sorry Bill,
still, nothing Deleted.
Is anything ECHOing to the console when you run it?


»bp
Avatar of W.E.B

ASKER

when I run the .bat you mean?
it runs so fast, I can't see what it's doing
Are you running it from a CMD window, so that you can see the display after it ends?  If not then do it that way, rather than just launching it from Explorer or the Run tool.


»bp
Avatar of W.E.B

ASKER

I ran it from the command line
I see all the Exho

last few lines
C:\Users\Wassim>REM Process all files, delete if too old
\EZSH was unexpected at this time.
Okay, I figured out the problem, and while I was correcting that cleaned up the code a small amount.  Now the folders to clean are a single list at the top, and we loop over that so that the logic isn't duplicated.  Give this a try and see how it goes for you.

@echo off
setlocal EnableDelayedExpansion

REM Define base for folder, and days to keep old files
set BaseDirs="C:\Program Files (x86)\EZSH 3.2","C:\Program Files (x86)\EZSH 3.2\CSV Exporter\NEW CSV Exporter\Export Invoice"
set KeepDays=30

REM Get current date in YYYYMMDD format, convert to julian
set LocalDateTime=
for /f "tokens=* skip=1" %%A in ('wmic os get LocalDateTime') do (
    if not defined LocalDateTime (
        set LocalDateTime=%%A
    )
)

REM Should never happen, but just be be extra safe
if not defined LocalDateTime exit /b

REM Convert current date to julian, suptract days to keep, convert cutoff back to YYYYMMDD gregorian
call :jDate jToday %LocalDateTime:~0,8%
set /a jKeepDate=jToday-KeepDays
call :gDate KeepDate %jKeepDate%

REM Process all folders we want to clean
for %%D in (%BaseDirs%) do (

    REM Make sure this folder exists
    if exist "%%~D\" (

        REM Process all files, delete if too old
        for /f "tokens=*" %%A in ('dir /a-d /b "%%~D\*-*.20??????.txt" "%%~D\*-*.20??????.csv" "%%~D\*-*.20??????.xls" "%%~D\*-*.20??????.xlsx"') do (
            set FileName=%%~nA
            ECHO Checking file:"%%~D\%%~A", Date:"!FileName:~-8!"
            if !FileName:~-8! LSS %KeepDate% (
                echo Removing File:"%%~D\%%~A", Date:"!FileName:~-8!"
                ECHO del "%%~D\%%~A"
            )
        )

    ) else (

        echo Missing folder:"%%~D"

    )

)

REM Done
exit /b

REM Subroutine to calculate julian date from (YYYYMMDD) date
:jDate [return-variable] [date-string]
    set DateStr=%~2
    set yy=%DateStr:~0,4%
    set /A mm=1%DateStr:~4,2%-100
    set /A dd=1%DateStr:~6,2%-100
    set /a "yy=10000%yy% %%10000,mm=100%mm% %% 100,dd=100%dd% %% 100"
    set /a %~1=dd-32075+1461*(yy+4800+(mm-14)/12)/4+367*(mm-2-(mm-14)/12*12)/12-3*((yy+4900+(mm-14)/12)/100)/4
    exit /b

REM Subroutine to calculate gregorian date in (YYYYMMDD) format from julian date
:gDate [return-variable] [date-string]
    set /a L=%~2+68569,N=4*L/146097,L=L-(146097*N+3)/4,I=4000*(L+1)/1461001
    set /a L=L-1461*I/4+31,J=80*L/2447,K=L-2447*J/80,L=J/11
    set /a J=J+2-12*L,I=100*(N-49)+I+L
    set /a YYYY=I,MM=100+J,DD=100+K
    set MM=%MM:~-2%
    set DD=%DD:~-2%
    set %~1=%YYYY%%MM%%DD%
    exit /b

Open in new window


»bp
Avatar of W.E.B

ASKER

Fantastic.
Thank you very much.
Welcome, sorry to drag that out so much...


»bp
FWIW, using that list would work for the PowerShell code too:
$age = 30
$folder = "C:\Program Files (x86)\EZSH 3.2","C:\Program Files (x86)\EZSH 3.2\CSV Exporter\NEW CSV Exporter\Export Invoice"

$dt = get-date (get-date).AddDays(-$age) -f 'yyyyMMdd'
get-childitem $folder |
  ? { $dtFile = ($_.BaseName -split '\.')[-1]; $dtFile -like '2???????' -and $dtFile -le $dt } |
  Remove-Item -WhatIf

Open in new window

That is, only the variable $folder needs to be changed from single value to array.
Q,

That's so long and wordy...

;-)
Oh, we can use aliases like gci and del to make it shorter :p.