Unix - delete files and folders excluding PATTERN

Recently I was faced with the task of deleting all the files/folders in a directory excluding those matching a specific pattern. So I cooked up a single-line unix command to do the work. Must it be only one line? I suppose not, but it's definitely cooler that way!

While the problem is pretty simple, I was a little surprised at how complex my solution ended up being. Here's the command I used; NOTE: this is a poor solution because it doesn't handle filenames containing line-feed characters (which didn't matter in my situation).

ls | grep -v PATTERN | xargs -n1 -IREPLACE rm -rf REPLACE

I did not use the "find" command because I do not want to recurse into folders matching PATTERN. For example, consider the following file structure:

file_foo.txt
first_dir
  |
  +--> contents
  +--> ...
foo_dir
  |
  +--> anotherfile.txt
  +--> morefiles.log
foo_file.txt
somefile.txt

Using pattern "foo" must only remove "first_dir" (and it's contents of course) and "somefile.txt" (not "anotherfile.txt" or "morefiles.log").

Question, are there better (more elegant and correct) ways to accomplish this?


EDIT:
It was recently brought to my attention that "find" may be a better option:

find * -maxdepth 0 ! -name PATTERN -print0 | xargs -0n1 rm -rf

This solution does correctly handle paths containing line-feed characters.


The following examples have echo prefixed so that you can test the patterns before actually using them. Remove the echo to activate the rm -rf. Substitute rm -ri to prompt for confirmation.

ksh has a negative match extension to its globbing:

# ksh
echo rm -rf !(*foo*)

The same syntax is available in bash if you set the extglob option:

# bash
shopt -s extglob
echo rm -rf !(*foo*)

zsh has its own syntax for this:

# zsh
setopt extended_glob
echo rm -rf ^*foo*

It can also use the ksh-style syntax:

# zsh: ksh-style glob syntax
setopt ksh_glob no_bare_glob_qual
echo rm -rf !(*foo*)

# zsh: ksh-style glob syntax, adapted for the default bare_glob_qual option
setopt ksh_glob bare_glob_qual
echo rm -rf (!(*foo*))

Here's another find solution. I'm not sure this has any real advantage over yours, but it doesn't need xargs and allows for the rare possibility that * expands to too many names.

find . -maxdepth 1 ! -name PATTERN -type f -delete

I also added -type f so that it would not attempt to delete directories.

Warning: -delete is powerful. I gave one of my test files 0 permissions and the command above deleted it without hesitation.