tags:

views:

51

answers:

5

hi

i have bunch of dirs , say *a, b, c0, d, Z , foo, * and so on.

I want to remove all the directories except dirs foo, foo2, a and b

can anyone provide me the syntax to do this shell?

Thanks

UPDATE I just want to say Thank you to all of you for your responses!

+3  A: 

Probably the easiest way;

mkdir ../tempdir
mv foo foo2 a b ../tempdir
rm *
mv ../tempdir/* .
rmdir ../tempdir

Please note that this deletes also all files, not just directories.

Kimvais
ah! That's it! In fact I also want to delete files. Thanks very much!
cppb
+4  A: 
echo `ls -1 -d */ | egrep -v '^(foo|foo2|a|b)/$'`

If you are satisfied with the output, replace echo with rmdir (or rm -r, if the directories still contain data).

Heinzi
no need for the -1.
ghostdog74
thanks, I tried this and it works fine.
cppb
Put up the `$()` or backtick escaped example as well?
Kimvais
@Kimvais: Good idea, I've updated my answer.
Heinzi
+1  A: 

You can use find on a complicated command line, but perhaps the simplest and, more importantly, safest way is to create a file that lists all of the directories you want to remove. Then use the file as input to rm like this:

find . -maxdepth 1 -type d > dirs_to_remove

Now edit the file and take out any directories you want to keep, then use rm:

rm -ir $(<edited_dirs_to_remove)

Note the -i argument. It's optional and forces rm to ask you before deleting each file. Also note the $(<filename) syntax, which is specific to bash and is equivalent to, but cheaper than $(cat filename).

Adam Liss
+1  A: 

one way

find . -maxdepth 1 -type d \( ! -name "bar" -a ! -name "foo" -a ! -name "a" -a ! -name "b" \) -delete  # to remove files as well, remove -type d

OR try using extglob

shopt -s extglob
rm -rf !(foo|bar|a|b)/  # to delete files as well, remove the last "/"

And yes, this assume you don't want the rest of the directories in your directory except the 4 directories you want.

ghostdog74
!!! WARNING !!! This assumes there are no subdirectories under a, b, bar, and foo. The names of the subdirectories do NOT match the criteria, and they will be deleted.
Adam Liss
thank you. info on extglob is useful.
cppb
Moral: NEVER execute a bulk delete command unless you've verified that it will do what you expect. In the case of find, simply remove the -delete command. In general, test the command by replacing "rm" with "ls"
Adam Liss
+1  A: 

One of the more powerful ways to do this sort of trick is using find + grep + xargs:

DONT_REMOVE='a|b|c0|d|Z|foo'
find . -type d -print | egrep -v "^\.$DONT_REMOVE\$" | xargs rm -r

The only trick here is making sure the pattern matches only those you don't want to remove. The above pattern only matches files in the current directory. You can make it more or less permissive, e.g:

IF_PATH_IS_IMMEDIATE_SUBDIR="^\./($DONT_REMOVE)$"
IF_PATH_ENDS_IN="/($DONT_REMOVE)$"
IF_PATH_CONTAINS="/($DONT_REMOVE)(/.*)?$"

Then pass one of these in your egrep, e.g:

find . -type d -print | egrep -v "$IF_PATH_ENDS_IN" | xargs rm -r

To invert the choice (ie. delete all those items) just remove the -v from the egrep

Dean Povey
You can simplify this by adding "-maxdepth 1" to the find command. "Find" is a lot like "make" -- I'm never done learning it. :-)
Adam Liss
Thanks. I wasn't sure if one level of subdirs was all that was needed, hence the different options.
Dean Povey
`find` (at least the GNU version) has `-regex` so you could eliminate `egrep`. Also, if you do `find ... -print0 | egrep -z ... | xargs -0 ...` your command will work with files that have spaces in their names.
Dennis Williamson