8

I noticed today (after ~8 years of happily hacking away at bash) that there is no trivial way to 'delete by date' using ´rm'. The solution is therefore to pipe stuff around a combination of commands like rm, ls, find, awk and sed.

Say for example I wanted to delete every file in the working directory from 2009, what would be the typical approach?

I came up with the following, which is butt-ugly and should only be run if 'rm' is set to skip over directories (otherwise you will delete the parent directory):

ls -la | awk '{if (substr($6,0,5)==2009) print $8}' | xargs rm

Points for both the most elegant and the most outrageously over-engineered solutions.

tshepang
  • 12,111
  • 21
  • 91
  • 136
Fergie
  • 5,933
  • 7
  • 38
  • 42

5 Answers5

11

I would combine find and rm (without pipe)

find .  ...bunch of find criterias to select certain files (e.g. by date) .... -exec rm \{\} \;

EDIT: with parameters for your example it would be

find . -maxdepth 1 -type f -ctime -12 -exec rm \{\} \;

CAVEAT: This works just today :-). (To make it work everytime, replace the -ctime with absoulte time, see timeXY in the manpage )

Hank Gay
  • 70,339
  • 36
  • 160
  • 222
flolo
  • 15,148
  • 4
  • 32
  • 57
  • Example here: http://www.howtogeek.com/howto/ubuntu/delete-files-older-than-x-days-on-linux/ – OIS Jan 12 '09 at 09:14
  • Is there any danger of "rm" interpreting a file name as a command switch in this scenario, and thus deleting too little or too much? – Rob Kennedy Jan 12 '09 at 09:36
  • @Rob: Partially: "-exec" calls rm with only one argument each time, so there's only the danger to delete too little. You could replace "rm \{\} \;" with "rm -- \{\} \;" to avoid that. – Joachim Sauer Jan 12 '09 at 09:41
  • `\{\}` is superfluous; just use `{}` – porges Feb 05 '09 at 22:56
10

Some versions of find support the -delete option, making it even more efficient...

find . -maxdepth 1 -type f -ctime -12 -delete;

Check your find man page (this has worked on most recent releases of Ubuntu for me)

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
  • nice- I like that there are no pipes or -execs – Fergie Jan 14 '09 at 12:59
  • Nice, except that it doesn't use rm as required in the question. I'm not trolling: using rm is a valid requirement if, for example, you want to use -i for interactive delete... – Alastair Jun 13 '09 at 12:17
  • Where "ctime" indicates that the file's 'Changed timestamp' (in days/24hr periods) was updated: ON/EXACTLY: no sign on number BEFORE/EARLIER: negative sign AFTER/LATER: positive + sign. Hence above example deletes files which were changed more than 12 days ago from now. – MikeW Aug 14 '17 at 16:31
  • Note: Busybox 'find' does not support ctime and several other related options. – MikeW Aug 14 '17 at 16:32
3

I would use:

find . -maxdepth 1 -type f -newerct 'jan 1' -print0 \
    | xargs -0 rm

(or -newermt if you want to filter on modification time)

Note that the 't' form of -newerXY will allegedtly allow any date format compatible with cvs (see doco).

Alastair
  • 4,475
  • 1
  • 26
  • 23
1

find(1) is a much more efficient to do what you want than parsing ls(1) output.

EDIT: something to watch for is filenames with spaces in them so you want to have a find which supports -print0 (to be used with xargs -0) for better performance.

find . -mtime +12 -print0 | xargs -0 rm -f
Keltia
  • 14,535
  • 3
  • 29
  • 30
1

Instead of parsing ls(1) which can too easily break you should rely on stat(1):

stat -c '%z/%n' files_or_glob | grep '^date' | cut -d/ -f2- | xargs -d '\n' rm -i

e.g.

$ stat -c '%z/%n' *| grep '^2008-12-16' | cut -d/ -f2- | xargs -d '\n' rm -i

Note: this will not handle filenames with embedded newlines correctly. However they are rarely found in the wil.d

ordnungswidrig
  • 3,140
  • 1
  • 18
  • 29