3

How do I remove all *.foo in a directory tree?

rm -r *.foo

does not work.

I could try a loop, but that needs recursive expansion:

for x in */*/.../*.foo
    do rm $x
done

Which is not possible either.

user877329
  • 738
  • 1
  • 5
  • 16
  • [How can I make chown work recursively?](http://superuser.com/questions/260925/how-can-i-make-chown-work-recursively) is basically the same question, except with `chown` instead of `rm`. – Ilmari Karonen Dec 23 '13 at 13:46

4 Answers4

9

You can use find:

find -name '*.foo' -delete
cYrus
  • 21,379
  • 8
  • 74
  • 79
  • Would this work? shouldn't it be `find . -name`? – Rob Dec 23 '13 at 19:24
  • 1
    @Rob, `man find`: _If no paths are given, the current directory is used_. – cYrus Dec 23 '13 at 19:50
  • @cYrus find is indeed really powerful. It lacks two actions that probably is easy to implement: *-callso youraction.so* and *-cfunc foo.c* . The shared object only needs to export a function void doIt(const char* path). That would be *really* powerful. – user877329 Dec 24 '13 at 09:22
  • @user877329, there's the `-exec` action that can be used for that purpose. – cYrus Dec 24 '13 at 11:25
  • @cYrus. Not really. It requires staring and stopping processes which is much slower. See mtak:s answer below. – user877329 Dec 24 '13 at 11:32
  • 1
    @user877329, I see your point, but in my experience these tools are good for getting things done quickly and easily, but if you need to do it _right_ then you often have to start developing your own tool. – cYrus Dec 24 '13 at 11:47
  • @cYrus thanks! I've been putting in `.` when I didn't need all this time! I'll save like, 20 seconds in the rest of my life now! – Rob Dec 27 '13 at 20:23
4

Assuming you have a fairly recent version of bash:

shopt -s globstar
rm -- **/*.foo
evilsoup
  • 13,097
  • 3
  • 59
  • 80
1

You could try using find:

find /dir/path -name *.foo -exec rm -f {} \;
arco444
  • 381
  • 1
  • 8
0

One of the easiest solutions would be to use the find command with the exec parameter:

find /path/where/to/start/search -type f -name "*.foo" -exec rm {} \;

This will look for all files named *.foo and perform rm {filename} for each one.

If you have lots of files, use of the xargs command may be faster:

find /path/where/to/start/search -type f -name "*.foo" | xargs rm 

This will find all files, and will put the file names behind the rm command up until the max length of a command your distro/shell will support, so when run it'll to this:

rm dir1/file1.foo dir1/file2.foo dir1/file3.foo 

As you can imagine now the rm binary needs to be started much less, making this a faster option.

mtak
  • 16,513
  • 2
  • 52
  • 64
  • 2
    Just to be safe, I'd suggest replacing `| xargs` with `-print0 | xargs -0`. By default, xargs splits its input on any whitespace, which could produce unwanted results if any file or directory names had spaces in them. The extra switches make find and xmarks use null bytes, which are not allowed in filenames, as separators instead. – Ilmari Karonen Dec 23 '13 at 13:49
  • I'd just use the -delete flag. – Rob Dec 23 '13 at 19:25
  • Not all versions of find include the -delete flag (for example on Solaris <11), so using `xargs` or `-exec` is more universal. – mtak Dec 24 '13 at 11:29