48

I need to delete all compiled data:

  • directories called build,
  • directories called obj,
  • *.so files.

I wrote a command

find \( -name build -o -name obj -o -name *.so \) -exec rm -rf {} \;

that goes through all the directories recursively and deletes all I need.

Why do I have such an output at the end? Maybe I should write a different command.

find: `./3/obj': No such file or directory
find: `./3/build': No such file or directory
find: `./1/obj': No such file or directory
find: `./1/build': No such file or directory
find: `./2/obj': No such file or directory
find: `./2/build': No such file or directory
4
  • on what system you are ? you should always use find like this find /search_directory options omiting the search directory is not a good idea
    – Kiwy
    Commented Feb 19, 2014 at 9:22
  • Automated deleting like this is a bad idea. You could have a script give you candidates, which you should then look at to make sure you are not deleting anything important or necessary to the system. You aren't explicit where you are running this. If you are only doing this in a user space, I suppose it can't do much harm, but you should make sure you are not doing this in a system area accidentally. You definitely want to run such a script as user. Commented Feb 19, 2014 at 9:43
  • @Kiwy,@FaheemMitha, the command will only be used in the project directoty; it will not do any harm there. Commented Feb 19, 2014 at 10:29
  • Related: stackoverflow.com/questions/22462124/… Commented Aug 29, 2019 at 10:43

3 Answers 3

87

Use -prune on the directories that you're going to delete anyway to tell find not to bother trying to find files in them:

find . \( -name build -o -name obj -o -name '*.so' \) -prune -exec rm -rf {} +

Also note that *.so needs to be quoted as otherwise it may be expanded by the shell to the list of .so files in the current directory.

The equivalent of your GNU -regex-type one would be:

find . \( -name build -o -name obj -o -name '*?.so' \) -prune -exec rm -rf {} +

Note that if you're going to use GNU specific syntax, you might as well use -delete instead of -exec rm -rf {} +. With -delete, GNU find turns on -depth automatically. It doesn't run external commands so in that way, it's more efficient, and also it's safer as it removes the race condition where someone may be able to make you remove the wrong files by changing a directory to a symlink in-between the time find finds a file and rm removes it (see info -f find -n 'Security Considerations for find' for details).

find . -regextype posix-egrep -regex '.*/((obj|build)(/.*)?|.+\.so)' -delete
6
  • -delete also handles things like spaces better
    – Izkata
    Commented Feb 19, 2014 at 15:33
  • @Izkata, not better than -exec rm -rf {} + which doesn't have issue with those either. Commented Feb 19, 2014 at 15:43
  • 1
    @grebneke, I think there's a post somewhere that claims quotes might be needed in very old versions of csh, but I never could verify that claim. They're not needed in any modern shell that I know. They're definitely not required by POSIX. The POSIX examples don't use them. Commented Mar 4, 2014 at 15:18
  • 5
    And -delete can't be used with directories. Commented Jun 16, 2016 at 16:21
  • 1
    @StOrM, -delete can be used with directories but will only delete empty directories, so you need to make sure your expression selects all the files inside the directory in addition to the directory itself (not that -delete implies -depth). Commented Jun 16, 2016 at 19:53
13

I guess the reason is that find deletes the directory tree first and tries to check the directory contents which is obviously not the best possible order. You can force find to check the contents first:

find . -depth ...

You should consider using -delete for files and -exec rmdir for directories.

0
0

My solution.

find . -regextype posix-egrep -regex ".*/(obj|build|.+\.so)" -prune -exec rm -rf {} +

+ vs \; in the -exec command

3
  • That's not always going to work, only if no boundary between executions happens inside a deleted directory. Commented Feb 19, 2014 at 23:14
  • @Gilles, what does "boundary between executions" mean? Commented Feb 26, 2014 at 7:41
  • 1
    -exec … {} + executes the command for multiple files at a time, as many as fit on the command line. If there are too many files (or more precisely if the total length of the paths is too long), find will execute multiple instances of rm, and thus may end up removing a directory that it's traversing. It's just less likely with + than with ;, but + doesn't solve the problem. Commented Feb 26, 2014 at 9:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .