Bash script to delete files older than x days with subdirectories

37

18

I'm trying to delete a ton of files older than x days.

Now I have a script to do that

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

But this will also delete the subdirectories. There are a ton of folders but I would like to keep them, and delete the files older than 10 days within the said folders.

Is there a way to do this?

JoyIan Yee-Hernandez

Posted 2012-01-05T16:18:13.733

Reputation: 487

Answers

50

type option for filtering results

find accepts the type option for selecting, for example, only files.

find /path/to/files -type f -mtime +10 -delete

Leave out -delete to show what it'd delete, and once you've verified that, go ahead and run the full command.

That would only run on files, not directories. Use -type d for the inverse, only listing directories that match your arguments.


Additional options

You might want to read man find, as there are some more options you could need in the future. For example, -maxdepth would allow you to only restrict the found items to a specific depth, e.g. -maxdepth 0 would not recurse into subdirectories.

Some remarks

  • I wonder how the command would have removed a folder, since you can't remove a folder with rm only. You'd need rm -r for that.

  • Also, /path/to/files* is confusing. Did you mean /path/to/files/ or are you expecting the wildcard to expand to several file and folder names?

  • Put the {} in single quotes, i.e. '{}' to avoid the substituted file/directory name to be interpreted by the shell, just like we protect the semicolon with a backslash.

slhck

Posted 2012-01-05T16:18:13.733

Reputation: 182 472

-mtime doesn't seem to work on windows with git bash, but works fine on unix so that's ok :) – GabLeRoux – 2014-10-17T13:30:37.013

I need to delete all files and subfolder inside a directory, in cron. I use this command, but it delete also the first directory. Ex. I wanto to remove all the files inside /var/download/, when I run the command it removes the "download" directory too. How to avoid this? – Kreker – 2015-06-05T09:25:30.187

@Kreker That shouldn't happen. If you use -type f it will only delete files, not directories. find /var/download -type f -mtime +10 should be enough. – slhck – 2015-06-05T09:29:41.710

@slhck in the "download" dir there are directories too. I need to empty the whole "download" directory, I used the command without -type, but the first result is the directory itself. – Kreker – 2015-06-05T12:17:33.203

1@Kreker Then you need to add -mindepth 1 to exclude the parent directory. – slhck – 2015-06-05T12:22:47.420

@slhck yeah! works like a charm thank you very much! +1 +1 – Kreker – 2015-06-05T12:38:53.577

Any idea why this wouldn't work inside a shell script? I always get an unknown predicate `-delete error – scsimon – 2017-05-03T14:26:44.423

@scsimon Make sure you are using GNU find, and that your shell script is not using a stripped down version of find that does not support it. – slhck – 2017-05-03T14:43:58.567

Well there are a lot of folders within /path/to/files/ actually I would like to run the mtime +10 -exec rm to each of those folders but keep the folders itself, basically I would like to achieve is that delete all the files older than 10days and keep all the folders. I'm a newb sorry bout that newbness :) – JoyIan Yee-Hernandez – 2012-01-05T16:26:45.593

Well, there you go :) Just do a find /path/to/files* -type f -mtime +10 and see what it would output. – slhck – 2012-01-05T16:28:22.523

Yup, when in doubt, don't do the -exec, just see what it finds first. – Rob – 2012-01-05T17:19:53.727

2@JoyIanYee-Hernandez You can also use the -delete argument to find, which deletes all files and folders, the latter only if empty. It implies -depth, i.e. depth-first search. – Daniel Beck – 2012-01-05T17:40:31.837

This gives argument list too long error if there are too many files. Could someone provide an iterative version? – cen – 2014-05-20T23:37:33.423

@cen This only happens if the path you give to find is expanded, which is only the case when there is a glob in it (e.g. *). Make sure you supply only a real directory as an argument. I'll fix my answer. – slhck – 2014-05-21T05:11:12.573

5

As in previous answers (+1 for both) the trick is to use -type f predicate.

Note, that instead of -exec rm '{}' you can also use -delete predicate. But don't do that. With -exec rm '{}' you can (and should) first do -exec echo rm '{}' to verify that this is really what do you want. After that rerun the command without the echo.

Using -delete is faster (no extra fork() and execve() for each file), but this is risky because -delete works also as a condition, so:

# delete *.tmp files
find . -type f -name '*.tmp' -delete

but if you ONLY swap arguments:

# delete ALL files
find . -type f -name '*.tmp' -delete

If you ever need find and rm to work faster for tons of files, check out the find ... | xargs ... rm UNIX idiom.

Michał Šrajer

Posted 2012-01-05T16:18:13.733

Reputation: 2 495

4I think your last two examples are exactly the same, might want to correct that! – slhck – 2012-05-23T18:11:51.040

1

You can easily do this with the find command

$ find -type f

Which restricts the results to be of the type file

Bernhard

Posted 2012-01-05T16:18:13.733

Reputation: 1 017

1

I was struggling to get this right using the scripts provided above and some other scripts especially when files and folder names had newline or spaces.

Finally stumbled on tmpreaper and it has been worked pretty well for us so far.

tmpreaper -t 5d ~/Downloads


tmpreaper  --protect '*.c' -t 5h ~/my_prg

Original Source link

Has features like test, which checks the directories recursively and lists them. Ability to delete symlinks, files or directories and also the protection mode for a certain pattern while deleting

user52573

Posted 2012-01-05T16:18:13.733

Reputation: 121

0

To speed up the command use '+' instead of \;

find /path/to/files* -type f -mtime +10 -exec rm '{}' '+'

This will run rm only once at the end instead of each time a file is found.
(rm may be run several times if your have really tons of files because of the command line length limitation, but this is still almost as fast as using -delete)

olibre

Posted 2012-01-05T16:18:13.733

Reputation: 1 533

0

rm -f find /path/to/files -type file -mtime -5

This will delete the files that are modified within 5 days

rm -f find /path/to/files -type file -mtime +5

This will delete the files that are modifed prior 5 days

Use ` before find and at the end after 5.

Nikhil Shinde

Posted 2012-01-05T16:18:13.733

Reputation: 1