2

I have 10 files in current directory:

10test
1test
2test
3test
4test
5test
6test
7test
8test
9test

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 '15 at 8:17
  • I just tried rm ^(2test|3test), still doesn't work – Aaron Shen Dec 1 '15 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 '15 at 8:20
  • zsh 5.0.8 (x86_64-apple-darwin14.3.0) – Aaron Shen Dec 1 '15 at 8:23
  • 1
    Your version is fine, make sure you set extendedglob. – Marco Dec 1 '15 at 8:25
7

!(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 '15 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 '15 at 9:05
6

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 ^.

0

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.