为什么即使打开 kshglob 也不能在 zsh 中使用 !(single pattern)?

ded*_*sdi 8 zsh wildcards

这适用于 bash:

touch a b c
echo !(a)
Run Code Online (Sandbox Code Playgroud)

如果我在 zsh 中执行上面的脚本(kshglob打开),它会抱怨:

zsh: number expected
Run Code Online (Sandbox Code Playgroud)

如果我在|之后添加a,它会起作用:

echo !(a|)
Run Code Online (Sandbox Code Playgroud)

为什么?

Sté*_*las 12

因为在这种情况下,它与裸 glob 限定符冲突,因为它位于模式的末尾。*(a1)取为最后一天访问的文件。(a1)被视为全局限定符。因此,在您的!(a)情况下, zsh 抱怨aglob 限定符(此处应用于名为 的文件!)后缺少天数。

zshglobs 中,(...)分组主要用于(foo|bar)交替,因此添加 a|是一种记录方式,以确保尾随(...)不被视为 glob 限定符。

另一个记录在案的替代方法是将括号 ( !((a)))加倍,或者您可以添加一个空的 glob 限定符(如!(a)(-))。

要完全消除这种歧义,可以关闭bare_glob_qual选项 ( set +o bareglobqual),之后必须使用extendedglob (#q...)语法 ( *(#qa1)here)编写 glob 限定符。

kshglob选项(在 1998 年添加,大致在同一时间bash添加,extglob尽管 bash 在此之前没有任何扩展的 glob)主要用于ksh仿真模式 ( emulate ksh),以便zsh能够运行ksh脚本,其中kshglob启用和bareglobqual禁用。首次引入时,启用 后kshglob,您需要指定 glob 限定符-(...)以避免这种冲突,但这会导致过多的混淆并与、和选项的@-(...)语法冲突。ksh93(#q...)bareglobqual

zsh用户一般都喜欢的zsh自己的扩展水珠(set -o extendedglob)运算符它们更容易输入(大多数)和更强大的(除启用了ksh88者kshglob中也发现bash -O extglob)。

例如,!(foo)会写成^foo. !(foo|)bar然而,等价物会更长,如(^(foo|))bar.

其他 ksh88 -> zsh 翻译:

  • *(x) -> x#
  • +(x) -> x##
  • @(x|y) -> x|y
  • ?(x) -> (x|)

一些 ksh93 -> zsh 翻译:

  • ~(i:x)-> (#i)x(不区分大小写)
  • ~(N)x-> x(N)(nullglob,起源于zsh)
  • {1,5}(x) -> x(#c1,5)
  • @(foo&bar)->foo~^bar^(^foo|^bar)

有些只在zsh

  • <1-23> (十进制数的范围)
  • pattern~except
  • pattern(glob-qualifier) (zsh globs 的杀手锏)
  • (pattern/)#(匹配pattern; 的任何级别的子目录最近也添加到 ksh93 和 bash的**/简化版本(*/)#
  • ***/* (符号链接后的递归通配符)。
  • (#a1)foobar (近似匹配,允许一些错误,这里1)
  • ...