views:

753

answers:

4

Hi,

I'm trying to do something which is probably very simple, I have a directory structure such as:

dir/
    subdir1/
    subdir2/
        file1
        file2
        subsubdir1/
            file3

I would like to run a command in a bash script that will delete all files recursively from dir on down, but leave all directories. Ie:

dir/
    subdir1/
    subdir2/
        subsubdir1

What would be a suitable command for this?

+8  A: 
find dir -type f -print0 | xargs -0 rm

find lists all files that match certain expression in a given directory, recursively. -type f matches regular files. -print0 is for printing out names using \0 as delimiter (as any other character, including \n, might be in a path name). xargs is for gathering the file names from standard input and putting them as a parameters. -0 is to make sure xargs will understand the \0 delimiter.

xargs is wise enough to call rm multiple times if the parameter list would get too big. So it is much better than trying to call sth. like rm $((find ...). Also it much faster than calling rm for each file by itself, like find ... -exec rm \{\}.

liori
+1, tested as good :-)
Grundlefleck
+5  A: 
find dir -type f -exec rm {} \;

where dir is the top level of where you want to delete files from

Note that this will only delete regular files, not symlinks, not devices, etc. If you want to delete everything except directories, use

find dir -not -type d -exec rm {} \;
Tyler McHenry
+1, tested as good :)
Grundlefleck
+1. I added the quotes, because they are essential when handling filenames which contain whitespace.
Stephan202
@Stephan202 That is incorrect. `'{}'` is the same as `{}` as far as the shell is concerned, and `find` sees just `{}` as the shell removes the quotes before passing the command-line arguments to `find`.
John Kugelman
@John. You're right. I stand corrected :)
Stephan202
It depends on the shell, really. "Brace expansion" can happen in new bash or zsh. That's why I am always escaping them.
liori
+3  A: 
find dir -type f -exec rm '{}' +
Jörg W Mittag
What is the '+' does?
Grundlefleck
The `-exec` command can be terminated in two ways: with a semicolon or a plus sign. If you use a semicolon, then a new process is spawned for every single file. If you use a plus sign, then only one process is spawned. (Well, actually, if the commandline gets too long, then multiple processes are spawned – basically, it works like `xargs` but without all the quoting problems.) Say, you have two files, called A and B. Then, with semicolon two processes would be spawned: `rm A` and `rm B`. With plus, only one process gets spawned: `rm A B`.
Jörg W Mittag
Cool, thanks.
Grundlefleck
+3  A: 

With GNU's find you can use the -delete action:

find dir -type f -delete

With standard find you can use -exec rm:

find dir -type f -exec rm {} +
John Kugelman
+1 for the -delete flag :)
Christoffer