为什么即使我打开 kshglob 也无法在 zsh 中使用 !(单一模式)?

为什么即使我打开 kshglob 也无法在 zsh 中使用 !(单一模式)?

这在 bash 中有效:

touch a b c
echo !(a)

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

zsh: number expected

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

echo !(a|)

为什么?

答案1

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

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

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

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

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

zsh用户通常更喜欢 zsh 自己的扩展 glob ( set -o extendedglob) 运算符,它更容易键入(对于大多数人来说)并且功能更强大(比kshglob中也启用的 ksh88 运算符更强大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 glob 的杀手级功能)
  • (pattern/)#(与 匹配的任何级别的子目录pattern;最近也将**/的简化版本(*/)#添加到 ksh93 和 bash 中)
  • ***/*(符号链接后的递归通配符)。
  • (#a1)foobar(近似匹配,允许有一些误差,这里1)
  • ...

相关内容