220

I have found the command to delete files older than 5 days in a folder

find /path/to/files* -mtime +5 -exec rm {} \;

But how do I also do this for subdirectories in that folder?

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Teddy77
  • 2,883
  • 7
  • 23
  • 34
  • Do you mean files inside the sub directories? or the sub directories themselves? – rahul Apr 07 '15 at 16:35
  • 3
    `find /path/to -type d -empty -delete` – Costas Apr 07 '15 at 16:39
  • 2
    Delete files in subdirectories that are also 5+ days old – Teddy77 Apr 07 '15 at 16:46
  • 3
    Possibly fun when I have files with spaces. E.g a file called "test one" and rm gets fed `rm test one`. (Which will delete a file called "test" and a file called "one", but not a file called "test one"). Hint: -delete or -print0 – Hennes Apr 07 '15 at 17:17
  • 6
    As a side note, **always quote the argument provided by `find`** to avoid issues with special characters, as mentioned in the answer's first line. E.g.: `find /path/to/files/ -exec somecommand '{}' \;` – Walf Jun 17 '16 at 01:54
  • @Walf The only reason one would want to quote `{}` is if one's shell treats that 2-character string specially. I believe `(t)csh` does this, but no other shell that I know of. You don't have to quote `{}` in e.g. `bash`, no matter what filenames you come across. The POSIX standard guarantees that each found pathname will be given to the utility as a separate argument. – Kusalananda Apr 03 '20 at 15:57
  • @Kusalananda or if you're writing a command that may end up getting executed in another shell like `fish`. Don't make assumptions, better safe than sorry, etc. Makes it obvious that it's an argument to `find`, like when you have to quote glob patterns inside `-name` (and related) arguments. – Walf Apr 04 '20 at 12:28
  • The easiest way is the below . You can first check the file names count with the below for the last 2 months , then verify and check , then delete the files . find . -iname "*.gz" -mindepth 1 -mtime +60 | wc -l Then check the files find . -iname "*.gz" -mindepth 1 -mtime +60 -print Once verified you can delete the same . find . -iname "*.gz" -mindepth 1 -mtime +60 | xargs rm -f – Seth Projnabrata Nov 21 '20 at 07:20

4 Answers4

394

Be careful with special file names (spaces, quotes) when piping to rm.

There is a safe alternative - the -delete option:

find /path/to/directory/ -mindepth 1 -mtime +5 -delete

That's it, no separate rm call and you don't need to worry about file names.

Replace -delete with -depth -print to test this command before you run it (-delete implies -depth).

Explanation:

  • -mindepth 1: without this, . (the directory itself) might also match and therefore get deleted.
  • -mtime +5: process files whose data was last modified 5*24 hours ago.
gilad905
  • 103
  • 3
basic6
  • 6,105
  • 4
  • 24
  • 29
  • 38
    Also use `-type f` to delete files only (and keep sub directories) – Oleg Mar 04 '16 at 08:44
  • 4
    Alternatively, if you want to do the same for all files NEWER than five days: find /path/to/directory/ -mindepth 1 -mtime -5 -delete – zmonteca Apr 19 '16 at 17:29
  • If my path contains spaces how should I do it? `find /path/to/dir\ with\ spaces/ -mindepth 1 -mtime +5 -delete`? – dokgu May 23 '17 at 19:59
  • 3
    @uom-pgregorio I would suggest putting the path in quotes. – atripes Oct 06 '17 at 14:40
  • I have a cronjob running once a week to delete those scratch files than inevitably accumulate on the disk: ``find /path/to/scratch/space -mtime +60 -print -delete``. So from time to time cron emails me telling me which files I just lost ... – Rolf Mar 20 '18 at 08:13
  • The timestamp of a folder might be older than the timestamp of file within a subfolder of that folder, i.e. in `/a/b/c.txt`, ``c.txt`` could be young and `a` old (in terms of mtime). And ``find`` could potentially find only one of them (assuming `-mindepth` is not set). However, `-delete` will not delete non-empty folders. – Rolf Jun 12 '18 at 08:52
  • not on Solaris. – access_granted Aug 07 '18 at 21:02
  • find /path/to/directory/ -mtime +5 -exec rm -rf {} \; <<- would be a SunOS version. -mindepth also doesn't work there. – access_granted Aug 07 '18 at 21:14
  • 35
    Note that every `find` argument is a filter that uses the result of the previous filter as input. So make sure you add the -delete as the last argument. IE: `find . -delete -mtime +5` will delete EVERYTHING in the current path. – Johan Jan 01 '19 at 11:39
  • 4
    With option `-mmin` in place of `-mtime`, you can specify time in terms of minutes. – zyy Jan 30 '20 at 02:31
  • 1
    There is no issue with using `-exec rm {} \;`. The pathname of the argument will be properly delimited by `find`, no matter what the filename is. It is _not_ "piping to `rm`". This answer resolves the issue, not by using `-delete`, but by using a directory path as the initial search path instead of a bunch of file paths (this is not even mentioned in the answer). – Kusalananda Apr 03 '20 at 15:48
  • unix `find` command is indeed a very _powerful_ tool – João Pimentel Ferreira Jun 21 '21 at 18:18
  • I found that `-delete` will work with very large lists of files, whereas `-exec rm {} \;` can fail if the list of matches is too long. – Franchesca Oct 25 '21 at 10:46
23

Note that this command will not work when it finds too many files. It will yield an error like:

bash: /usr/bin/find: Argument list too long

Meaning the exec system call's limit on the length of a command line was exceeded. Instead of executing rm that way it's a lot more efficient to use xargs. Here's an example that works:

find /root/Maildir/ -mindepth 1 -type f -mtime +14 | xargs rm

This will remove all files (type f) modified longer than 14 days ago under /root/Maildir/ recursively from there and deeper (mindepth 1). See the find manual for more options.

Julius
  • 466
  • 4
  • 9
  • 9
    Per @AfshinHamedi's answer on AskUbuntu (https://askubuntu.com/questions/589210/removing-files-older-than-7-day), be careful with files containing newlines and special characters. Instead use `find /root/Maildir/ -mindepth 1 -type f -mtime +14 -print0 | xargs -r0 rm --` – Cbhihe Jul 12 '16 at 08:17
  • 2
    Or just add '+' to the find results – Dani_l Apr 02 '17 at 11:07
13

It's the same. You just have to provide the parent directory rather than the prefix of files. In your example, it would be:

find /path/to -type f -mtime +5 -exec rm {} \;

This will delete all the files older than 5 days which are under /path/to and its sub-directories.

To delete empty sub-directories, refer to @Costas comment above.

apaul
  • 3,338
  • 1
  • 15
  • 15
  • 4
    Note that for each and every file you will execute the rm command. If you have 1000 files older than 5 days then rm will get started 1000 times. For this reason consider the -delete option as in Costa's comment or -exec rm {} \+ – Hennes Apr 07 '15 at 17:14
  • @Hennes: -- 1) not sure you need to escape `+` in that case. -- 2) better to write `-exec rm '{}' +` to fend off the evil of files with special characters (spaces, newlines, etc...) in their name. – Cbhihe Jul 12 '16 at 09:04
  • Note that with `-exec rm {} +`, if there are too many files, `rm` may complain: `Argument list too long`. So yes, `-delete` does seem like the much more sensible option. – mwfearnley Oct 29 '21 at 13:48
-1
find . -mtime +3 -type f -not -name '*pid*' |xargs rm -rf
Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
Susil
  • 11