Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I store some data in files which follow this naming convention:


How do I look for the ones with date in file name < now - 1 month and delete them?

Files may have changed since they were created, so searching according to last modification date is not good.

What I'm doing now, is filter-ing them in python:

prefix = '/interesting/data/filename-'

import commands
names = commands.getoutput('ls {0}*'.format(prefix)).splitlines()

from datetime import datetime, timedelta

all_files = map(lambda name: {
    'name': name,
    'date': datetime.strptime(name, '{0}%Y-%m-%d-%H-%M'.format(prefix))
}, names)

month = - timedelta(days = 30)
to_delete = filter(lambda item: item['date'] < month, all_files)

import os
from operator import itemgetter
map(os.remove, map(itemgetter('name'), to_delete))

Is there a (oneliner) bash solution for this?

share|improve this question
up vote 1 down vote accepted

Can you use -ctime with find? For a file, ctime indicates the last time the file metadata has changed (file creation, rename, chmod, chown, chgrp, etc). For most logfiles, creation date and ctime would be the same.

share|improve this answer
According to man find: -ctime n File’s status was last changed n*24 hours ago. That only returns filenames from that exact date, but in my case there may be files older than than, and I can't tell how old they are, so I really need a ` < ` or ` <= ` comparison. – Martin Tóth Jan 13 '11 at 8:33
You are right. man find says: Numeric arguments can be specified as: +n (for greater than n), -n (for less than n), n (for exactly n). And it works as desired. Thanks! – Martin Tóth Jan 14 '11 at 9:40

Presuming GNU date and GNU find you can do it this way

#!/usr/bin/env bash


# create a file whose timestamp is "one month ago"
touch "$one_month_ago" -t $(date -d "-1 month" +%Y%m%d%I%M.%S)

while read -r file ; do
        # strip the prefix, leaving the suffix
        datestr=$(tail -c $(( ${#file} - ${#prefix} + 1 )) <<<"$file")

        # cut the date and time out of the suffix
        date=$(cut -d- -f1-3 <<<"$datestr")
        time=$(cut -d- -f 4- <<<"$datestr" | tr - :)

        # create a reference file whose timestamp matches the string from $file
        touch "$ref" -t $(date -d "$date $time" +%Y%m%d%I%M.%S)

        # ask find whether the reference file is not neewer (aka "is older") 
        # than one month ago
        find "$ref" -not -newer "$one_month_ago" > "$results" &&
                # results from find?
                [ -s "$results" ] &&
                # then rm the corresponding file
                echo rm -f -- "$file"

done < <(find -path "$prefix"'*')

# clean up
rm -f "$ref" "$one_month_ago" "$results"

But it's not exactly a oneliner.

Since this is under tested and somewhat dangerous I have included an echo prefix to the rm command, so you'll need to remove that once you verify that the results are correct.

One weakness here is in the initial selection of files. -path "$prefix"'*' presumes absolute paths and will break otherwise; a more intelligent selection is probably better, even if it's a simple shell glob (i.e., replace the while loop with for file in "$prefix*" ; do ... done. I didn't do this because I don't know whether or not such a glob expansion would overflow the maximum command length.

share|improve this answer
Thank you for your effort! – Martin Tóth Jan 14 '11 at 9:40
Interesting, it actually does the compares. It will be a bit slower because of all the touch files. The find . ! -newer' can much more simply be replaced by the [ $FILE1 -ot $FILE2 ]` flag, at least in bash. – Rich Homolka Jan 14 '11 at 16:22
Given all of the GNUisms present, including the explicit invocation of bash and the use of non-portable find syntax, I don't think anyone could object to the use of -ot. I would have used this comparison if I had thought about it, but instead I recycled a solution I've used before (when I had GNU find on Windows, but no sh). – phogg Jan 14 '11 at 17:10
As it turns out you can use -newerXY where Y is t to specify a timestamp directly (for GNU find it's GNU date -d format) to avoid the need to create an intermediate file. This will be a little faster, as Rich mentions. – phogg Jan 26 '11 at 0:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .