30

The command

$ find ~ -name .DS_Store -ls -delete

works on Mac OS X, but

$ find ~ -name __pycache__ -type d -ls -delete

does not - the directories are found but not deleted.

Why?

PS. I know I can do

$ find ~ -name __pycache__ -type d -ls -exec rm -rv {} +

the question is why find -delete does not work.

33

find's -delete flag works similar to rmdir when deleting directories. If the directory isn't empty when it's reached it can't be deleted.

You need to empty the directory first. Since you are specifying -type d, find won't do that for you.

You can solve this by doing two passes: first delete everything within dirs named __pycache__, then delete all dirs named __pycache__:

find ~ -path '*/__pycache__/*' -delete
find ~ -type d -name '__pycache__' -empty -delete

Somewhat less tightly controlled, but in a single line:

find ~ -path '*/__pycache__*' -delete

This will delete anything within your home that has __pycache__ as part of its path.

  • On find 4.4.2, that last command needs to be find ~ -path '*/__pycache__*' -delete, or probably find ~ -path '*/__pycache__/*' -o -name __pycache__ -delete to be safe. – naught101 Aug 24 '16 at 1:18
  • 3
    @naught101, that should be find ~ \( -path '*/__pycache__/*' -o -name __pycache__ \) -delete as and has precedence over or. – Stéphane Chazelas Aug 24 '16 at 11:36
6

There are a couple potential reasons for this.

1) You told it to delete directories only (-type d), and those directories still have files inside them.

2) Your directories only contain other directories, so the -type d will take care of the contents issue. However you are using OS-X, which is largely based on FreeBSD, and the FreeBSD find by default will process the directory before its contents.
However the -depth option exists to solve this problem by telling find to process the directory after its contents.

find ~ -name __pycache__ -type d -ls -delete -depth

This issue does not exist on linux because the -delete option implicitly enables -depth.

 

FreeBSD man 1 find:

 -depth  Always true; same as the non-portable -d option. Cause find to
   perform a depth-first traversal, i.e., directories are visited in
   post-order and all entries in a directory will be acted on before
   the directory itself. By default, find visits directories in
   pre-order, i.e., before their contents. Note, the default is not
   a breadth-first traversal.

GNU man 1 find:

 -depth Process each directory's contents before the directory itself. The -delete
        action also implies -depth.
  • 2
    Yeah, but FreeBSD’s find(1) says for -delete, “… Depth-first traversal processing is implied by this option.”, and GNU find(1) says, “… -delete implies -depth, …”, so it shouldn’t be necessary to add -depth to the command. – G-Man Oct 30 '14 at 16:17
  • 1
    From the GNU find manpage: "To prevent confusion, global options should specified on the command-line after the list of start points, just before the first test, positional option or action. If you specify a global option in some other place, find will issue a warning message explaining that this can be confusing." Now, -delete is a "global option" after the ~ in the command given. I have also noticed that it makes no difference whether you add -depth or not. Nonempty directories stay undeleted (but that's probably because I use -maxdepth too) – David Tonhofer Sep 17 '17 at 17:20

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.