This works in bash:
touch a b c
echo !(a)
If I execute above script in zsh (with kshglob
on), it complains:
zsh: number expected
If I add |
after a
, it works:
echo !(a|)
Why?
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityBecause in this case, it conflicts with bare glob qualifiers since it's at the end of the pattern. *(a1)
is taken as the files last accessed in the last day. (a1)
is treated as a glob qualifier. So in your !(a)
case, zsh complains about the missing number of days after the a
glob qualifier (here applied to the file called !
).
In zsh
globs, (...)
grouping is mostly used for the (foo|bar)
alternation, so adding a |
is a documented way to make sure a trailing (...)
is not treated as a glob qualifier.
Another documented alternative is to double the parenthesis (!((a))
) or you could add an empty glob qualifier (like !(a)(-)
).
To completely remove that ambiguity, one can turn off the bare_glob_qual
option (set +o bareglobqual
), after which glob qualifiers have to be written with the extendedglob
(#q...)
syntax (*(#qa1)
here).
The kshglob
option (added in 1998, roughly the same time bash
added its extglob
though bash didn't have any extended glob before that) is mostly there for the ksh
emulation mode (emulate ksh
), for zsh
to be able to run ksh
scripts, where kshglob
is enabled and bareglobqual
is disabled. When it was first introduced, after enabling kshglob
, you'd need to specify glob qualifiers as -(...)
to avoid that kind of conflict but that caused too much confusion and conflicted with the @-(...)
syntax of ksh93
, the (#q...)
and bareglobqual
options were introduced later.
zsh
users generally prefer zsh's own extended glob (set -o extendedglob
) operators which are easier to type (for most) and more powerful (than the ksh88 ones enabled with kshglob
also found in bash -O extglob
).
For example, !(foo)
would be written ^foo
. The !(foo|)bar
equivalent would however be longer like (^(foo|))bar
.
Other ksh88 -> zsh translations:
*(x)
-> x#
+(x)
-> x##
@(x|y)
-> x|y
?(x)
-> (x|)
Some ksh93 -> zsh translations:
~(i:x)
-> (#i)x
(case insensitive)~(N)x
-> x(N)
(nullglob, originated in zsh){1,5}(x)
-> x(#c1,5)
@(foo&bar)
-> foo~^bar
or ^(^foo|^bar)
Some only found in zsh
:
<1-23>
(range of decimal numbers)pattern~except
pattern(glob-qualifier)
(the killer feature of zsh globs)(pattern/)#
(any level of subdirectories matching the pattern
; the **/
simplified version of (*/)#
was also added to ksh93 and bash recently)***/*
(recursive globbing following symlinks).(#a1)foobar
(approximate matching, allowing some errors, here 1)