To delete all non-hidden files and directories last modified longer than 2 weeks ago, I'm using:

find ~ -mindepth 1 -mtime +14 -name "[!.]*" -delete

This will sometimes print error messages "Directory not empty".

I would like to silence these errors (as I get notified about them when running as a cronjob) but I would still like find to delete directories when they are empty and older than 2 weeks.

  • 1
    Instead of -delete, you can use -exec with rm -rf – Raman Sailopal Oct 4 '17 at 8:36
  • @RamanSailopal, that could recursively delete directories that contain recently modified files! – Stéphane Chazelas Oct 4 '17 at 8:49
  • Fair point. Always run the find without delete or exec first to ensure that the listing is as you expect! – Raman Sailopal Oct 4 '17 at 8:58

If your find supports the -maxdepth and -delete non-standard extensions, it likely also supports -empty, so you can do:

find ~ -mindepth 1 -mtime +14 ! -name '.*' \( ! -type d -o -empty \) -delete

(that is, only attempt to delete directories that are empty)

Note that -delete implies -depth (which you'd expect as you'd want to delete a file before the directory that contains it).

However, deleting a file from a directory updates the modification time of that directory. That means that directories won't be deleted if they contained old files that have been successfully deleted even if they were old themselves initially.

Here, you may want to not delete any directory at all:

find ~ -mtime +14 ! -name '.*' ! -type d -delete

Or record the list of old directories before deleting any file, delete the non-directory files, and then delete the directories in the recorded list:

tmp=$(mktemp) &&
  rm -f -- "$tmp"
  find ~ -depth -mindepth 1 ! -name '.*' -mtime +14 -type d -print0 >&3
  find ~ -mtime +14 ! -name '.*' ! -type d -delete
  xargs -r0 rmdir <&4 2> /dev/null
} 3> "$tmp" 4< "$tmp"

Or using moreutils sponge (though that means storing the whole list of files in memory):

 find ~ -depth -mindepth 1 ! -name '.*' -mtime +14 -type d -print0 |
   sponge sh -c '
     find ~ -mtime +14 ! -name ".*" ! -type d -delete
     xargs -r0 rmdir'

Or zsh's =(...) form of process substitution:

  find ~ -mtime +14 ! -name ".*" ! -type d -delete
  xargs -r0 rmdir
} < =(find ~ -depth -mindepth 1 ! -name '.*' -mtime +14 -type d -print0)

Or you could delete all empty directories regardless of whether they're old or not:

find ~ -mindepth 1 ! -name '.*' \( -mtime +14 ! -type d -o -type d -empty \) -delete

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.