为什么 zsh 和 ksh93 在模式匹配中选择不合规?

cuo*_*glm 7 shell ksh zsh

模式匹配的 POSIX 文档说:

普通字符是一种匹配自身的模式。它可以是支持字符集中的任何字符,除了 NUL、Quoting 中需要引用的那些特殊 shell 字符以及以下三个特殊模式字符。匹配应基于用于编码字符的位模式,而不是基于字符的图形表示。如果引用了任何字符(普通、shell 特殊或模式特殊),则该模式应与字符本身匹配。shell 特殊字符总是需要引用。

据我了解,该模式["!"a]将匹配!和中的任何一个a。这也是我尝试过的大多数 shell 中的行为,除了zshksh93

$ for shell in /bin/*[^c]sh; do
  printf '=%-17s=\n' "$shell"
  "$shell" -c 'case a in ["!"a]) echo 1;; esac'
done
=/bin/ash         =
1
=/bin/bash        =
1
=/bin/dash        =
1
=/bin/heirloom-sh =
1
=/bin/ksh         =
=/bin/lksh        =
1
=/bin/mksh        =
1
=/bin/pdksh       =
1
=/bin/posh        =
1
=/bin/schily-osh  =
1
=/bin/schily-sh   =
1
=/bin/yash        =
1
=/bin/zsh         =
Run Code Online (Sandbox Code Playgroud)

zsh并且ksh93似乎对待["!"a]与 相同[!a],它匹配任何字符,除了a

$ for shell in ksh93 zsh; do
  printf '=%-6s=\n' "$shell"
  "$shell" -c 'case b in ["!"a]) echo 1;; esac'
done
=ksh93 =
1
=zsh   =
1
Run Code Online (Sandbox Code Playgroud)

是否有任何原因(历史,发展,...)zshksh93那样做的?


zsh在两者kshsh仿真中做同样的事情。

busybox sh, Solaris/usr/xpg4/bin/sh和 FreeBSDsh也表现得像 POSIX 文档。


ksh88也像大多数其他 shell 一样,行为在kssh88和之间发生了变化ksh93

$ ksh88 -c 'case a in ["!a"]) echo yes; esac'
yes
$ ksh88 -c 'case b in ["a-c"]) echo yes; esac' 
$
Run Code Online (Sandbox Code Playgroud)

Gil*_*il' 5

你引用的那段话并不代表你所说的意思。

匹配单个字符的模式

(...) 一个普通字符是一个匹配自身的模式。(...) 如果引用了任何字符(普通、shell 特殊或模式特殊),则该模式应与字符本身匹配。

所有这些仅适用于在模式中代表自己的字符。这不适用于出现在预期模式字符之外的上下文中的字符。特别是,它不适用于括号表达式内。括号表达式的语法在以下条目中描述[

如果一个开放括号引入一个括号表达式,如XBD RE Bracket Expression,(...)

(我省略了关于!vs 的部分^用于补充。)RE 方括号表达式的描述没有说明任何关于引用的内容(这并不奇怪,因为它通常是关于方括号表达式,而不是关于 shell 脚本中模式中的方括号表达式)。

根据对 POSIX.1-2008 的严格解释,不清楚该模式["!"a]应该匹配什么。一种解释是它应该匹配任何字符",!或者a: 该字符"在括号表达式中没有特殊含义。我在规范中找不到任何会使这种解释无效的内容。另一种解释是"保留其引用行为,但这意味着括号表达式的内容是!a,并且由于没有对括号表达式内的引用字符进行特殊处理,该集合是 all-but- a。我在 POSIX 规范中找不到对您的解释(以及破折号、bash 和其他 shell 的行为)的任何支持。这当然是有道理的,但这不是文字所说的。

通过为此添加一些措辞,POSIX 的未来版本可以强制您进行解释。例如,[可以将描述更改为

如果开括号引入了XBD RE Bracket Expression 中的括号表达式,除了 \ 字符 ( '!') 应替换 \ 字符 ( '^') 在正则表达式表示法中的非匹配列表中的作用,它应引入模式括号expression ,并且被引用的任何字符都应代表其自身作为括号表达式、整理元素或类表达式的元素。以未加引号的 \ 字符开头的括号表达式会产生未指定的结果。否则,'['应匹配字符本身。

鉴于 POSIX 主要是描述性的而不是规范性的,我希望这种破坏 ksh(通常是参考 shell)的更改只包含在标准的主要更新中,并且现有版本的任何缺陷至少允许现有的不同解释。