I have 10 files in current directory:


I want to remove all file except 2test and 3test, but I run command rm !(2test|3test) doesn't work. I get the following error:

zsh: no matches found: !(2test|3test)
  • 2
    Use ^(2test|3test), ! works for bash, zsh however uses ^.
    – Marco
    Dec 1, 2015 at 8:17
  • I just tried rm ^(2test|3test), still doesn't work
    – Aaron Shen
    Dec 1, 2015 at 8:18
  • 1
    touch {1..10}test; rm ^(2test|3test) leaves only the two files. If it doesn't work for you please provide your zsh version. Also make sure you use setopt extendedglob which is required for this to work.
    – Marco
    Dec 1, 2015 at 8:20
  • zsh 5.0.8 (x86_64-apple-darwin14.3.0)
    – Aaron Shen
    Dec 1, 2015 at 8:23
  • 1
    Your version is fine, make sure you set extendedglob.
    – Marco
    Dec 1, 2015 at 8:25

3 Answers 3


!(pattern) is ksh glob syntax, in zsh, you use ^(pattern) to negate the matching when extendedglob enabled:

setopt extendedglob
print -rl -- ^(2test|3test)

If you want to use ksh syntax, you need to enable kshglob:

setopt kshglob
print -rl -- !(2test|3test)

You can also use the and-not/except operator:

setopt extendedglob
print -rl -- *test~[23]*

(*test files except those that start with 2 or 3).

Also not that unless the nobareglobqual option is enabled or you use |s within them, trailing (...) glob grouping operators conflict with glob qualifiers. For example, in !(foo) or ^(foo), the foo would be treated as a glob qualifier. You'd need ^foo or !(foo)(#q) (the (#q) adds a non-bare (explicit) glob qualifier).

  • I am using zshell, ^ works for normal files, but it doesn't work for dot files. imagine I have a bunch of dot files. .a, .b, .c, .d ... . I want to remove all of them but keep .a and .b, using rm ^(.a|.b) doesn't work. Is there a way to do that?
    – Aaron Shen
    Dec 1, 2015 at 8:53
  • 1
    You need to use D qualifier to include dot file in globbing result, try print -rl -- ^(.a|.d)(D)
    – cuonglm
    Dec 1, 2015 at 9:05

When you use setopt extendedglob you can use ^(2test|3test) to remove all files except 2test and 3test:

# setopt extendedglob
# touch {1..10}test
# rm ^(2test|3test)
# ls
2test 3test

! is used by bash, zsh however uses ^.


starting with a clean (empty) zsh

 zsh -f 
 setopt extendedglob
 touch {1..10}test
 rm ^(2|3)test(.)

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.