According to the bash manual, if extglob
is enabled,
the pattern @(pattern-list)
should match any of the patterns in pattern-list
(separated by |
). Here it works as expected:
$ 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/
But if we swap the alternatives in each of the three pattern lists,
most of the directories that should have been matched are gone:
$ ls -ld /@(usr|.)/@(local|.)/@(share|.)/
drwxrwsr-x 10 root staff 4096 Oct 15 2018 /usr/local/share/
The same with a non-existing subdirectory. Here it works:
$ 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/
And here it doesn't:
$ ls -ld /@(usr|.)/@(foo|.)/@(share|.)/
ls: cannot access '/@(usr|.)/@(foo|.)/@(share|.)/': No such file or directory
What's going on here? Is this behavior documented somewhere, or is it just plain buggy? (This is GNU bash, version 4.4.12(1).)
Best Answer
Prior to bash-4.3, the "." term would never match. From bash(1), v5.0, section Pathname Expansion:
The description of the behaviour here is a little vague, but it doesn't mean that "." must be at the start of each (sub-)pattern, you can prove that with:
So the problem is specific to "." and not "..".
I believe this is a bug in
extglob_skipname()
, starting at line 218 in thewhile (t = glob_patscan (pp, pe, '|')) { ... }
loop, the final term in such a pattern is not handled properly (interaction with the leading "." supression logic inskipname()
) so "." never matches but ".." manages to match. (glob_patscan
is akaPATSCAN
thanks to macro games.)Either of these work too:
So the answer is the sub-pattern order shouldn't matter, and doesn't matter, but seemingly a bug causes problems when the final term is a ".".