1

I'm trying to figure out my old skill in *nix.

What I'm trying to achieve is to remove every folders that does not contain a specific word.

This is the listing

➜  myfolder: pwd
/user/myfolder

➜  myfolder: ll locale

drwxr-xr-x  3 user  staff  102 23 Oct 11:13 bn_BD
drwxr-xr-x  3 user  staff  102 23 Oct 11:13 bn_IN
drwxr-xr-x  3 user  staff  102 22 Oct 19:03 en_CA
drwxr-xr-x  8 user  staff  272  9 Dec 16:10 en_US
drwxr-xr-x  3 user  staff  102 22 Oct 19:03 es
drwxr-xr-x  3 user  staff  102 21 Oct 13:18 fr
drwxr-xr-x  3 user  staff  102 23 Oct 11:13 pt
drwxr-xr-x  3 user  staff  102 21 Oct 13:18 ru
drwxr-xr-x  3 user  staff  102 21 Oct 13:18 th_TH

Now I want to remove everything except en_US

I don't know what is the not in the command

rm -rf locale/[!somethinghere]

4 Answers 4

3

With GNU find (and possibly other versions too), you can use an exclamation mark to reverse a search -- so this will find and delete everything in the current directory except 'en_us':

find . ! -name 'en_US' -delete
##  If you only want to delete directories:
find . -type d ! -name 'en_US' -delete
##  If you *don't* want recursiveness:
find . -maxdepth 1 -type d ! -name 'en_US' -delete
##  If you want to avoid deleting dotfiles:
find . -maxdepth 1 -type d ! -name 'en_US' -a ! '.*' -delete

Some versions of find don't have the -delete option; instead you could use one of:

find . -maxdepth 1 -type d ! -name 'en_US' -exec rm -r '{}' +
find . -maxdepth 1 -type d ! -name 'en_US' -a ! '.*' -exec rm -r '{}' +

Alternatively, since you mentioned in a comment that you have zsh,

setopt extendedglob  ##  this may already be set in you .zshrc
rm ^*en_US*
##  If you only want to delete directories:
rm ^*en_US*(/)
13
  • Yours very similar to what I found except I can't seem to use -delete?
    – Ali
    Dec 9, 2013 at 23:17
  • What does find --version give you? Are you using GNU find, or something else?
    – evilsoup
    Dec 9, 2013 at 23:18
  • I just use find that built-in from my Mac OS X?
    – Ali
    Dec 9, 2013 at 23:19
  • 1
    Ahh. You should have specified OSX in your tags (I was wrongly assuming linux). It uses the BSD versions of the various command-line tools, while I'm used to the GNU versions that most linuxen use. Maybe try the new version of the command in the latest version of my answer.
    – evilsoup
    Dec 9, 2013 at 23:26
  • Sorry about that @evilsoup.. I should have mention that >.<
    – Ali
    Dec 9, 2013 at 23:28
1

A three-line solution will work (tested with Linux bash):

tar cvf foo $(find locale -name en_US)
rm -fr locale
tar xvf foo

That is:

  • Save what you want to keep
  • Delete original
  • Restore what you saved

I played around with something like find locale \( -name en_US -true \) -o -print | xargs ..., but this seems more complicated. And more risky, if one's Unix skills are rusty.

1
  • I would prefer the second option only if I can figure out why it keep matching "en_US" too
    – Ali
    Dec 9, 2013 at 22:44
0

This is what I end up doing.

find locale -type d ! -name 'en_US' ! -name 'locale' | xargs rm -rf

The reason I have to include "locale" as well because the xargs returned locale locale/bn_BD locale/bn_IN locale/en_CA locale/es locale/fr locale/pt locale/ru locale/th_TH

Now I have these deleted

#   deleted:    locale/bn_BD/goggles.webmaker.org.json
#   deleted:    locale/bn_IN/goggles.webmaker.org.json
#   deleted:    locale/en_CA/goggles.webmaker.org.json
#   deleted:    locale/es/goggles.webmaker.org.json
#   deleted:    locale/fr/goggles.webmaker.org.json
#   deleted:    locale/pt/goggles.webmaker.org.json
#   deleted:    locale/ru/goggles.webmaker.org.json
#   deleted:    locale/th_TH/goggles.webmaker.org.json
1
  • 1
    You shouldn't pipe find output to xargs, unless you use find … -print0 | xargs -0 ….
    – slhck
    Dec 10, 2013 at 8:11
0

You can do it using bash expansion: rm -rf path/to/!(something.*)

Edit:

As mentioned in comments below, this command works if extended globbing format is enabled.

You can enable it by command shopt -s extglob in bash or setopt kshglob in zsh.

4
  • 1
    I don't know if it is because of zsh but I'm getting this - zsh: no matches found: locale/!(en_US.*)/
    – Ali
    Dec 9, 2013 at 22:38
  • You need to use shopt -s extglob to enable this behaviour in bash; the syntax for zsh is different.
    – evilsoup
    Dec 9, 2013 at 22:51
  • @evilsoup I'm not sure what is this mean? shopt -s extglob ?
    – Ali
    Dec 9, 2013 at 22:55
  • If you were using bash, you would have to enter the command shopt -s extglob to enable extended globbing, which allows you to use the !(pattern*) syntax in this answer. But you are using zsh, which uses a different sort of extended glob. I think that if you enter the command setopt kshglob, you should be able to use this answer.
    – evilsoup
    Dec 9, 2013 at 23:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .