Thanks again for the info. Now I understand why `.' and `..' are handled separately, and I can imagine the complexity.
> The "matched explicitly" refers to the previous sentence, which talks about > the `.' at the start of a filename or path component needing to be matched > explicitly by a pattern beginning with a `.' or containing a `.' at the > right spot (after a `/'). I can add language to clarify that. What about this? | When a pattern is used for filename expansion, the character `.' at the | start of a filename or path component must be matched explicitly by a | corresponding `.' at the start of the pattern or after a `/', unless the | shell option dotglob is set. The character `.' at the start of the | filenames `.' and `..' must always be matched explicitly, even if dotglob | is set. In other cases, the `.' character is not treated specially. > > $ echo !(.foo) > > bar > > There is an equally compelling argument to be made that `.' and `..' should > be included in the results from the second example, since they do not match > the pattern `.foo'. The question is how much `not matching' you want. > `dotglob' only affects the `matching' state. That's the essence of where we > started with this. Yes, it all depends on the "universal set" from which the matches of the inner `pattern-list' are subtracted. But in the current implementation, the inner matches are subtracted from: - all files, if dotglob is set - all except dot files, if dotglob is unset The inclusion of `.' and `..' when dotglob is set, seems inconsistent with the exclusion of dot files when dotglob is unset. I think it would be most intuitive and useful to define the universal set to be whatever `*' can expand to. I.e. - all except `.' and `..', if dotglob is set - all except dot files, if dotglob is unset > I'm not averse to changing the current behavior. This is a niche case. > Then instead of figuring out language to describe the current behavior, > let's figure out language to describe the desired behavior. I would want to limit as much as possible the cases where a path component can expand to `.' or `..', which is always undesirable, but also remain consistent with non-extended globbing and keep it simple. With dotglob set, we can use `[.]' to match a starting dot without the risk of including `.' and `..'. I always use `[.]*' instead of `.*', so it comes natural that I need to use `@([.]*|foo)' instead of `@(.*|foo)'. But normally there's no need to protect the dot in `.foo*', so it doesn't come natural that I need to protect it in cases like `!([.]foo*)' or `@([.]foo*|??)'. With dotglob unset, the current behavior seems fine. > Your English is fine. You want to take a shot at a sentence or two > describing your desired behavior? It should not take more than that. About the behavior of the extended operators ?,*,+,@ (with my proposed changes when dotglob is set), I'm not sure there's a need for explanation. I think it comes natural if you mentally translate the extended pattern into a sequence of non-extended patterns. About `!()', we could say: | The `!()' operator will never match the character `.' at the start of a | filename, unless the shell option dotglob is set. Even if dotglob is set, | it will never match the character `.' at the start of the filenames `.' | and `..'. Or: | The `!()' operator can only match strings that can be matched by `*', so | the inclusion of filenames starting with the character `.' is affected by | the shell option dotglob in the same way. Regards, NP