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/

ただし、3つのパターンリストのそれぞれで代替を置き換えると、一致する必要があるほとんどのディレクトリが消えます。

$ 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別名Macro Gamesのおかげです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/

したがって、答えは、サブパターンの順序が重要でも重要でもないということです。ただし、最後のエントリが「.」の場合、バグが問題を引き起こす可能性があるようです。

関連情報