bash extglob:模式列表中模式的顺序是否重要?

bash extglob:模式列表中模式的顺序是否重要?

根据 bash 手册,如果extglob启用,该模式应与(以 分隔)@(pattern-list)中的任何模式匹配。这里它按预期工作:pattern-list|

$ shopt -s extglob
$ ls -ld /@(.|usr)/@(.|local)/@(.|share)/
drwxr-xr-x  50 root root   4096 Sep  2 16:39 /./././
drwxr-xr-x  12 root root   4096 Oct 15  2018 /usr/././
drwxrwsr-x  10 root staff  4096 Oct 15  2018 /usr/local/./
drwxrwsr-x  10 root staff  4096 Oct 15  2018 /usr/local/share/
drwxr-xr-x 725 root root  20480 Sep  2 16:42 /usr/./share/

但是,如果我们交换三个模式列表中每个模式中的替代项,则大多数应该匹配的目录都消失了:

$ ls -ld /@(usr|.)/@(local|.)/@(share|.)/
drwxrwsr-x 10 root staff 4096 Oct 15  2018 /usr/local/share/

对于不存在的子目录也是如此。在这里它起作用了:

$ ls -ld /@(.|usr)/@(.|foo)/@(.|share)/
drwxr-xr-x  50 root root  4096 Sep  2 16:39 /./././
drwxr-xr-x  12 root root  4096 Oct 15  2018 /usr/././
drwxr-xr-x 725 root root 20480 Sep  2 16:42 /usr/./share/

而这里却没有:

$ ls -ld /@(usr|.)/@(foo|.)/@(share|.)/
ls: cannot access '/@(usr|.)/@(foo|.)/@(share|.)/': No such file or directory

这里发生了什么?这种行为是否记录在某处,或者只是简单的错误? (这是 GNU bash,版本 4.4.12(1)。)

答案1

在 bash-4.3 之前,“.”术语永远不会匹配。来自 bash(1),v5.0,部分路径名扩展

                                                When a  pattern  is  used
  for  pathname expansion, the character ``.''  at the start of a name or
  immediately following a slash must be matched  explicitly,  unless  the
  shell  option  dotglob  is  set.  The filenames ``.''  and ``..''  must
  always be matched explicitly, even if dotglob is set.

这里对行为的描述有点模糊,但它意思是“.”必须位于每个(子)模式的开头,您可以通过以下方式证明:

$ echo  /@(usr|.)/@(local|.)/@(share|.)/
/usr/local/share/
$ echo  /@(usr|..)/@(local|..)/@(share|..)/
/../../../ /usr/../../ /usr/local/../ /usr/local/share/

所以问题是特定于“.”的。并不是 ”..”。

我相信这是一个错误extglob_skipname(),从while (t = glob_patscan (pp, pe, '|')) { ... }循环中的第 218 行开始,这种模式中的最后一项未正确处理(与 中的前导“.”抑制逻辑交互skipname()),因此“.”从不匹配,但“..”设法匹配。 (glob_patscan又名感谢PATSCAN宏游戏。)

其中任何一个也有效:

$ echo  /@(usr|.|)/@(local|.|)/@(share|.|)/
/./././ /usr/././ /usr/./share/ /usr/local/./ /usr/local/share/
$ echo  /@(usr|.|.)/@(local|.|.)/@(share|.|.)/
/./././ /usr/././ /usr/./share/ /usr/local/./ /usr/local/share/

所以答案是子模式顺序不重要,也不重要,但是当最后一项是“.”时,似乎一个错误会导致问题。

相关内容