I am trying to remove all contents of a directory with some exclusions. I'm currently using this:

find . -type f | grep -vZf ../../exclude.file | xargs rm -rf

The exclude.file contains:


I don't want to remove the world, log or crash-reports folders or any of their contents (the * is to cover backups, which are generated as world.zip).

The command above does this, but it does not remove non-empty directories. E.g. the Config directory is left, but I need it removed.

I've also experimented with similar to the following:

find -maxdepth 0 -not -name '*log*' -not -name 'crash-reports' -not -name 'world*' | xargs rm -rf

But I still get the same result.

Is there a way to do this?


-type f will only find files, not directories. -maxdepth 0 will only ever find the directory you're searching in (.). You'll have to find the files you actually want to pass to rm.

The standard way to do this is to exclude directories and all their contents like this (untested!):

find . -mindepth 1 \( -name '*log*' -o -name 'crash-reports' -o -name 'world*' \) -prune -o -print
  • Embarassing. Thanks! I should have spotted that. Removing type -f does what I want, but it pays no attention to '*logs*', deleting the logs folder. Specifying it as 'logs' leaves it alone but there will be 'abc.log' and 'thisisalog.txt' which I wanted to cover with *log*. Any suggestions? Jul 3 '14 at 12:14
  • That is not going to work but would delete the whole directory tree from the search point (in combination with rm -r). It is kind of ridiculous that this is the accepted answer. Jul 3 '14 at 12:32
  • I accepted the answer as it lead me to my answer. Your answer 'not possible' was less helpful, although valued and appreciated. I managed to get the desired result with: find . | grep -v -i -e "world" -e "logs" -e "crash-reports" -e "banned-*" | xargs rm -rf Jul 3 '14 at 12:55
  • @AndrewWright You don't know how grep works. The -e values are regular expressions. * in a regex does not what you obviously expect. Next problem: find . gives . as first result. Your grep matches . and rm -r . deletes the whole directory tree. Jul 3 '14 at 13:13
  • All files I want to keep are in the directory the command is run from. I do want to delete the whole directory tree. Jul 3 '14 at 14:28

What you want is not possible IMHO with a single find run unless you know that all the directories to be skipped are in the first directory level.

first step

In the first run delete all the files (or rather: non-directories):

find . \( -type d \
  \( -name '*log*' -o -name 'world*' -o -name 'crash-reports' -o -name 'banned-ips*' \) \
  -prune \) -o \( -type d -o -print \)

second step

Create a dummy file in each (sub)directory to be skipped:

find . -type d \( \
  \( -name '*log*' -o -name 'world*' -o -name 'crash-reports' -o -name 'banned-ips*' \) \
  -o \( -path '*/*log*/*' -o  -path '*/world*/*' -o  -path '*/crash-reports/*' -o  -path '*/banned-ips*/*' \) \) \
  -exec touch {}/dontdeletethisdirecory

third step

Now all empty directories can be deleted. The simple approach is to pass all directories to rmdir. Only the empty ones get deleted:

find . -depth -type d -exec rmdir {} \;

optional last step

You may now delete the dummy files:

find . -type -f -name dontdeletethisdirecory -delete

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.