Deleting files older than 30 days based on filename as date

If I have a folder of files with their filenames as the date they were created:

2019_04_30.txt
2019_04_15.txt
2019_04_10.txt
2019_02_20.txt
2019_01_05.txt

How would I compare the files names against todays current date

$ date "+%Y_%m_%d"
>>> 2019_04_30

If the file names date is greater than 30 days then delete it. I would expect to end up with

2019_04_30.txt
2019_04_15.txt
2019_04_10.txt

I don’t have to follow this naming convention, I could use a more suitable date format.

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

Here is a bash solution.

f30days=$(date +%s --date="-30 days")
for file in 20*.txt; do
    fdate=$(echo $file | tr _ -)
    fsec=$(date +%s --date=${fdate/.txt/})
    if [[ $fsec -lt $f30days ]]; then
        echo "rm $file"
    fi
done

I ended it with “echo rm $file” instead of really deleting your files, this will test the result before.

Solution 2

With zsh:

zmodload zsh/datetime
strftime -s start '%Y_%m_%d.txt' $((EPOCHSECONDS - 30*86400))
echo -E rm -i 2*.txt(e:'[[ $REPLY > $start ]]':)

Remove the echo -E when happy.

On a GNU system and with the GNU shell (bash), you could do something approaching with:

start=$(date -d '30 days ago' +%Y_%m_%d.txt)
list=()
shopt -s nullglob
for file in 2*.txt; do
  [[ $file > $start ]] && list+=("$file")
done
if (( ${#list[@]} > 0)); then
  echo -E rm -i "${list[@]}"
fi

Solution 3

This does not fit your answer exactly but I think you if work through the logic you will find many ways to work through your problem.

This is based on me wanting to check to see if a backup was made within the last 14 days based on the filename format “%username%.Backup.YEAR.MONTH.DAY.time.HOURS.MINUTES”

I believe in its current state it will fail to produce the correct result if you go above 28 days due to not looping through the if statement inside setlocal until days is no longer less than 1.

set year=%date:~10%
set month=%date:~4,2%
set day=%date:~7,2%
set /a day-=14
set /a leapyear=!(%year%%%4)
set numdays=31 28 31 30 31 30 31 31 30 31 30 31
if %leapyear%==1 set numdays=31 29 31 30 31 30 31 31 30 31 30 31

setlocal enabledelayedexpansion
    if %day% lss 1 (
        set /a month-=1
        if !month! lss 1 (
            set /a year-=1
            set /a month+=12
        )
        set mcount=0
        for %%A in (%numdays%) do (
            set /a mcount+=1
            if !mcount!==!month! set /a day+=%%A
        )
    )
    set day=0%day%
    set month=0%month%
endlocal & (set day=%day:~-2%)& (set month=%month:~-2%)& (set year=%year%)

for /f "tokens=3,4,5 delims=." %%A in ('dir /b /a:d /o:-n "%backuppath%" ^| findstr /r "%username%.Backup.*"') do (
    if %year%%month%%day% lss %%A%%B%%C (
        goto endofscript
    )
)

Solution 4

yyyy-mm-dd strings have a property that they’re alphabetically ordered. So just do:

fdate=$(date +%F --date="-30 days")
for file in 20*; do
    if [[ $file =~ [0-9]{4}-[0-9]{2}-[0-9]{2} && $file -gt $fdate ]]; then
        rm -rf "$file"
    fi
done

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply