2

I wrote the following in PHP but I was wondering if there is an elegant way to do this in a Linux shell script? Basically delete files over (n) days old, but leave the (n) newest files regardless of age.

    PHP

    foreach (glob("backup/*.db") as $file) {
        $a[$file]=date("Y-m-d",filemtime($file));
    }
    $i=0;
    arsort($a);
    foreach($a as $file=>$date) {
        if ($i++>=10) {
            if ($date<=date("Y-m-d",strtotime("-10 days"))) {
                unlink($file);
                xmessage("PURGED: $file");
            }   
        }   
    }   

My idea was to delete with "find -mtime +(n) exec rm" but only pipe in the files that are NOT in "head -n +(n)"? But "head -n" does not seem to do what I thought it would. Thanks.

SHELL SCRIPT

find -mtime +10 | ls -t *.DB.tar.gz | head -n -10

2 Answers2

2

Try this using all GNU find, sort, awk, and xargs:

find . -type f -printf '%Ts %p\0' |
sort -k1,1nr -sz |
awk -v days=10 -v cnt=10 '
    BEGIN { RS=ORS="\0"; secs=systime()-(days*24*60*60) }
    (NR>cnt) && ($1>secs) { print gensub(/\S+\s+/,"",1) }
' |
xargs -0 ls --

Change ls to rm when you're done testing and sure it's giving you the expected output.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • 1
    I would like to mark [this](https://stackoverflow.com/questions/20358865/remove-all-files-older-than-x-days-but-keep-at-least-the-y-youngest) question as a duplicate, but not a single answer seems correct. This answer actually belongs there. – kvantour Feb 15 '21 at 10:11
  • Thanks for your answer. But I guess it'd be better if we can explain all those options and awk commands as probably not everyone can understand those.. – Lam Le May 21 '21 at 09:56
  • 1
    @LamLe no, it's not necessary to explain every language construct used in every tool tagged in a question, If there's anything in my answer that someone doesn't understand a quick glance at the man page will fix that. – Ed Morton May 21 '21 at 12:07
  • It must be `$1secs`. Otherwise this will delete newer files. – nE0sIghT Feb 01 '22 at 17:15
1

If you have a version of find that cannot use -printf (f.ex. busybox), you can use this:

find ${FOLDER} -type f -exec stat -c "%y %-25n" {} \; |
sort -n |
head -n -$(MIN_FILES_TO_KEEP) |
cut -d ' ' -f3- |
xargs -r -I FILE find FILE -mtime +$(MIN_DAYS_TO_KEEP) |
xargs -n1 rm

I had to refactor the command to use in docker-compose and this was the result. It is not the most elegant or efficient solution though.

didac
  • 83
  • 1
  • 8