287

I want to delete all *.o files in a directory and its sub-directories. However, I get an error:

sashoalm@aspire:~/.Workspace.OLD$ rm -r *.o
rm: cannot remove `*.o': No such file or directory

On the other hand, rm *.o works, but it's not recursive.

4

2 Answers 2

457

That is evil: rm -r is not for deleting files but for deleting directories. Luckily there are probably no directories matching *.o.

What you want is possible with zsh but not with sh or bash (new versions of bash can do this, but only if you enable the shell option globstar with shopt -s globstar). The globbing pattern is **/*.o but that would not be limited to files, too (maybe zsh has tricks for the exclusion of non-files, too).

But this is rather for find:

find . -type f -name '*.o' -delete

or (as I am not sure whether -delete is POSIX)

find . -type f -name '*.o' -exec rm {} +
7
  • 11
    Can you please explain the curly braces and the plus sign in this context? Aug 18, 2016 at 16:53
  • 4
    works fine on macOS
    – To Kra
    Nov 22, 2016 at 9:36
  • 7
    @AubreyRobertson See the man page for find. -exec + (in contrast to -exec ;) handles several files at once. The {} is the place holder for the file name / path (in both cases). Jan 2, 2017 at 0:34
  • 5
    @stpoa I encourage you to try to find an example where my code does not work as intended. Sep 28, 2017 at 18:01
  • 1
    find has a delete flag. The things you learn each day. Excellent! Sep 21, 2020 at 14:52
79

That's not quite how the -r switch of rm works:

-r, -R, --recursive
          remove directories and their contents recursively

rm has no file searching functionality, its -r switch does not make it descend into local directories and identify files matching the pattern you give it. Instead, the pattern (*.o) is expanded by the shell and rm will descend into and remove any directories whose name matches that pattern. If you had a directory whose name ended in .o, then the command you tried would have deleted it, but it won't find .o files in subdirectories.

What you need to do is either use find:

find . -name '*.o' -delete

or, for non-GNU find:

find . -name '*.o' -exec rm -r {} \;

Alternatively, if you are using bash you can enable globstar:

shopt -s globstar
rm -r -- **/*.o

NOTE: all three options will delete directories whose name ends in .o as well, if that's not what you want, use one of these:

find . -type f -name '*.o' -delete
find . -type f -name '*.o' -exec rm {} \;
rm -- **/*.o
2
  • When I run this with -exec rm -rf, it deletes a folder I'm trying to match & remove, then errors with No such file or directory, and exit code is non-zero... Is there a way to get around this error? (operation was still a success) Aug 29 at 13:01
  • 1
    @SoylentGraham use -depth which makes find operate on the contents of a directory before the directory itself: find . -depth -name '*.o' -exec rm -rf {} \;
    – terdon
    Aug 29 at 13:04

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