179

I'm trying to work out a command which deletes sql files older than 15 days.

The find part is working but not the rm.

rm -f | find -L /usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups -type f  \( -name '*.sql' \) -mtime +15

It kicks out a list of exactly the files I want deleted but is not deleting them. The paths are correct.

usage: rm [-f | -i] [-dIPRrvW] file ...
       unlink file
/usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups/20120601.backup.sql
...
/usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups/20120610.backup.sql

What am I doing wrong?

jerrygarciuh
  • 21,158
  • 26
  • 82
  • 139

5 Answers5

343

You are actually piping rm's output to the input of find. What you want is to use the output of find as arguments to rm:

find -type f -name '*.sql' -mtime +15 | xargs rm

xargs is the command that "converts" its standard input into arguments of another program, or, as they more accurately put it on the man page,

build and execute command lines from standard input

Note that if file names can contain whitespace characters, you should correct for that:

find -type f -name '*.sql' -mtime +15 -print0 | xargs -0 rm

But actually, find has a shortcut for this: the -delete option:

find -type f -name '*.sql' -mtime +15 -delete

Please be aware of the following warnings in man find:

  Warnings:  Don't  forget that the find command line is evaluated
  as an expression, so putting -delete first will make find try to
  delete everything below the starting points you specified.  When
  testing a find command line that you later intend  to  use  with
  -delete,  you should explicitly specify -depth in order to avoid
  later surprises.  Because -delete  implies  -depth,  you  cannot
  usefully use -prune and -delete together.

P.S. Note that piping directly to rm isn't an option, because rm doesn't expect filenames on standard input. What you are currently doing is piping them backwards.

Lev Levitsky
  • 63,701
  • 20
  • 147
  • 175
  • 1
    Thanks. I read the man page and gave that flag a try. I'm passing a full path but getting back "/usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups/: relative path potentially not safe". Any idea why? – jerrygarciuh Jun 25 '12 at 15:25
  • 1
    @jerrygarciuh take a look [here](http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg16944.html). – Lev Levitsky Jun 25 '12 at 15:34
  • thanks. I am not sure I followed the post well but when I emulated their solution and put -delete at the end of the command it deleted all of the sql files regardless of mod time... but it didn't have the warning so I guess that's progress... – jerrygarciuh Jun 25 '12 at 16:13
  • 1
    @jerrygarciuh Ouch, I hope nothing valuable was lost... `man` says: `When testing a find command line that you later intend to use with -delete, you should explicitly specify -depth in order to avoid later surprises.` I'm not sure how that would matter given the other options you used, though, but did you try that? – Lev Levitsky Jun 25 '12 at 17:23
  • Nope I didn't but nothing was lost. These files are rsync-ed from another server where they are also stored. – jerrygarciuh Jun 25 '12 at 18:28
  • @jerrygarciuh um, so did you figure it out? was `'-depth'` the reason? – Lev Levitsky Jun 25 '12 at 20:06
  • Hi Lev, I don't actually know because our sysadmin took the job and resolved it some other way. So much for learning by doing! – jerrygarciuh Jun 26 '12 at 16:28
  • @sarat The second and third commands handle it correctly. In the 2nd command, a \\0 character is used to separate the arguments instead of a space. In the 3rd one, find handles it internally. – Lev Levitsky Jul 16 '15 at 11:39
  • ahhh finally!!! thank you so much this is great, I had no clue about xargs – Gregor Hartl Watters Oct 15 '22 at 19:29
35
find /usr/www/bar/htdocs -mtime +15 -exec rm {} \;

Will select files in /usr/www/bar/htdocs older than 15 days and remove them.

Michael
  • 8,362
  • 6
  • 61
  • 88
Suresh
  • 351
  • 3
  • 2
  • I prefer your answer than the one accepted because of the "space in the name". It's better handled with the "-exec" command than pipe. Thanks. – Slim Aloui May 03 '20 at 15:00
  • How to pipe the files deleted to a log file? ` rm {} >> my.log` doesn't fly. – Marc Nov 10 '21 at 07:47
13

Another simpler method is to use locate command. Then, pipe the result to xargs.

For example,

locate file | xargs rm
Gautam Sreekumar
  • 536
  • 1
  • 9
  • 20
  • This is what I was looking for. I didn't want to use `find` nor `locate`, hence there are faster alternatives. – lsd Jun 07 '22 at 12:30
5

Use xargs to pass arguments, with the option -rd '\n' to ignore spaces in names:

"${command}" | xargs -rd '\n' rm

Include --force if you want to also remove read only files.

4

Assuming you aren't in the directory containing the *.sql backup files:

find /usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups/*.sql -mtime +15 -exec rm -v {} \;

The -v option above is handy it will verbosely output which files are being deleted as they are removed.

I like to list the files that will be deleted first to be sure. E.g:

find /usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups/*.sql -mtime +15 -exec ls -lrth {} \;