Exclude from * in command line
For Bash there is a shell option called extglob
that is deactivated by default to keep compatibility with standard shell syntax. Extglob complements the syntax by additional operators like !()
, ?()
, @()
and some more.
To switch extglob
on, type shopt -s extglob
. To keep it switched on for the current user type echo 'shopt -s extglob' >> ~/.bashrc
.
For the rm example: With extglob
you can use
rm -rf !(one|two|three)
I've built except exactly for that (sry that I wasn't able to add documentation yet).
I you have a folder like the following:
$ ls
a b c d
Typing except b d
will give you a
and c
$ except b d
ac
Now you can pipe that to rm
.
except b d | xargs -0 rm
This may be hard to remember, so why not just build a script on top of except, called
rm-except
:
#!/usr/bin/env bash
except "$@" | xargs -0 rm
Similarly easy is ls-except
:
#!/usr/bin/env bash
except "$@" | xargs -0 ls
As an alternative to extglob (though that is a very good answer and everyone should have shopt -s extglob globstar
in their .bashrc), you can use the $GLOBIGNORE global variable. Let's say you want to get every file except 'foo.txt' and 'bar baz.txt':
GLOBIGNORE=foo.txt:'bar baz.txt'
...however, this will turn the shell option dotglob
on, which means that *
will match files beginning with a dot (which are normally hidden). So you actually need two commands:
GLOBIGNORE=foo.txt:'bar baz.txt'
shopt -u dotglob
Since this is a global variable, it will affect every glob you use until $GLOBSTAR is unset either by logging out or with
GLOBIGNORE=
It will also only work on the literal strings passed to the variable. You can see what I mean by setting $GLOBIGNORE and looking at the difference between these commands:
printf '%s\n' *
printf '%s\n' ./*