1

I want to delete file not by date access or created, but by filename. The filenames will be dates and I want to have a cronjob run once a week that will purge filename dates older than 7 days. I could do a

find /my/directory -type f -name '*file-name.yyyy-mm-dd.qz' -delete

But I would have to change the script on a weekly basis to run. I would like to avoid having to modify the job every week.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
CP24eva
  • 13

4 Answers4

3

Here is a more robust form that correctly handles spaces (or even newlines) in filenames and directory names.

find . -type f -name '*.[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].qz' -exec sh -c 'fdate="${1%.qz}"; fdate="${fdate##*.}"; [ "$fdate" "<" "$(date +%F -d "7 days ago")" ] && rm "$1"' find-sh {} \;

This involves a lot of shell trickery that might look alien to some people, so let's break it down:

Starting in the current directory, recursively find all regular files...

find . -type f

...whose names end in the exact pattern ".YYYY-MM-DD.qz"...

-name '*.[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].qz'

...then, run a shell command on each matching file (note the single quotes)...

-exec sh -c '

...which first strips off the trailing ".qz"...

fdate="${1%.qz}";

...then strips off the leading extra part, leaving only "YYYY-MM-DD"...

fdate="${fdate##*.}";

...and compares that string to see if it sorts (lexically) earlier than "YYYY-MM-DD" of the date seven days ago...

[ "$fdate" "<" "$(date +%F -d "7 days ago")" ]

...and if so, removes the file...

&& rm "$1"'

...and we'll use "find-sh" as the "script name" (i.e. $0) to be used for error reporting...

find-sh

...and set the filename found by find to parameter one ($1) of the inline shell script.

{} \;
Wildcard
  • 36,499
  • This requires the .qz extension, which OP may or may not want. – WAF Jun 06 '16 at 19:57
  • @WAF, the .qz extension is specified in the question itself. – Wildcard Jun 06 '16 at 20:02
  • 1
    command use seems pretty interesting. I'll have to take some notes from it. I found a really messy way of going about it that isn't so compact. This is interesting though. Thanks for taking the time out to explain it's parts. I'll give it a shot. – CP24eva Jun 07 '16 at 13:17
  • @CP24eva, glad I could help. If you're satisfied, please take a moment to "accept" the answer (mine or another's) that you believe is the best solution, by clicking the checkmark to the left of the answer. :) – Wildcard Jun 07 '16 at 16:53
1

I can't post a comment, but here is the command to create empty test files:

for i in {0..50};do touch blah.`date "+%Y-%m-%d" -d "$i days ago"`.qz  ;done

I believe Dave's answer does the trick. (I needed to complete the for command with '; do')

A great one liner for cron.

Jim
  • 221
0

You can use this:

find /my/directory -type f -name "*file-name.$(date -d '7 days ago' +%Y-%m-%d).qz" -delete 

This lets the shell tell us what date was 7 days a go: $(date -d '7 days ago' +%Y-%m-%d)

For example: if today is 2016-06-06 this will be: 2016-05-30

So, whenever your command is executed, that will take the date 7 days ago and so on.

I hope you understand me. If you need something, just comment.

muru
  • 72,889
  • 2
    This kind of works. The issue that I have it that when I run it then it find the file specifically "7 days ago" so anything names older than 7 days ago is left out. – CP24eva Jun 06 '16 at 17:33
0

I'll recommend a short script, basically gets all the filenames that have a date like format, then loops through them, checking if seven days ago is later than the date found in the filename, and if so, deletes it.

The date parsing basically makes an integer in the format YYYYMMDD and compares using that, which should work fine since the larger units have a higher factor of ten.

This is a rough script off the top of my head that I didn't get a chance to test.

for file in $(find /my/directory -type f -name "*file-name.[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].qz")
    if [ $(date -d '7 days ago' +"%Y%m%d") -ge $(date -d $(echo $(basename $file) | cut -d '.' -f 2) +"%Y%m%d") ]; then
        rm $file
    fi
 done
Centimane
  • 4,490
  • 1
    I don't think you need to reformat the date strings. You can just compare the date with format +%Y-%m-%d to those 10 characters in the file name (e.g. [ date -d '7 days ago' +%Y-%m-%d -ge echo $(basename $file) | cut -d '.' -f 2 ]) since the given format is already sorted lexically. Also, the cut you suggest will only work if there are no periods in file names. – WAF Jun 06 '16 at 19:43
  • @WAF -ge is for numerical comparison. > and < are for lexical comparison and are more appropriate. But you are correct that the date strings don't need reformatting. (Also the basename/cut combination is much more complicated than it needs to be; you can just use shell parameter expansion.) – Wildcard Jun 06 '16 at 19:47
  • @Wildcard Yeah, too much copy and pasting on my part. That should be [[ ... > ... ]], and I agree that ${filename##*.} might be in order, but a lot still depends on consistency of file names. – WAF Jun 06 '16 at 19:51
  • @WAF re depending on filename consistency: not really. The pattern passed to the -name primary (in both this answer and my answer) specifies the exact pattern, so anything that doesn't match exactly that pattern simply won't be processed. – Wildcard Jun 06 '16 at 19:55