Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Inconsistent behavior with comparisons and recursive glob patterns



Thanks - I did miss that **/ wasn't supported in conditional expressions.

I wonder if there might be some value in making that explicit in the
documentation, possibly by changing the paragraph you referenced to
something like this:

    Pattern metacharacters are active for the pattern arguments. The patterns
    are the same as those used for filename generation, see zshexpn(1), but
    there is no special behaviour of `/' nor initial dots, shorthand operators
    such as **/ are not converted to their expanded forms, and glob qualifiers
    are only allowed for forcing filenames to be generated as described above.

There's a slight issue that "such as **/" implies there are many
shorthand operators; I have no idea if there are any others besides
**/ and ***/.

Thanks,
Awk

On Tue, Apr 30, 2024 at 9:11 AM Eric Cook <llua@xxxxxxx> wrote:
>
> On 4/30/24 04:14, Alan Wagner-Krankel wrote:
> > The results of these conditional expressions using recursive glob
> > operators were unexpectedly different:
> >
> >> [[ f0 = **/f? ]] && print true || print false
> > false
> >> setopt extendedglob
> >> [[ f0 = (*/)#f? ]] && print true || print false
> > true
>
> A couple things about [[:
>
> ```
> Pattern metacharacters are active for the pattern arguments; the patterns  are
> the  same  as those used for filename generation, see zshexpn(1), but there is
> no special behaviour of ‘/' nor initial dots, and no glob qualifiers  are  al‐
> lowed.
> ```
>
> That last bit about glob qualifiers is out of date since you can now use them to
> force filename generation on in [[. but the point is you aren't doing filename
> generation in [[ (by default), which is where **/ is shorthand for (*/)#.
> pattern matching/globbing is tightly coupled to filename generation in unix shells
> but there are difference.
>
> Even when you use a glob qualifier to force filename generation to happen, you
> still wasn't going to get the behavior you desired since the pattern would've
> underwent filename generation before the comparison that [['s =/== does.
>
> % (set -x; [[ f0 = **/f?(#qN) ]]; touch f2; [[ f0 = **/f?(#qN) ]])
> +zsh:3> [[ f0 =  ]]
> +zsh:3> touch f2
> +zsh:3> [[ f0 = f2 ]]
>
> >
> > Since **/ is a shorthand version of (*/)#, it seems like they both
> > should have returned 'true'. The comparisons behave the same when
> > there is at least one directory in the path:
> >
> >> [[ d1/f1 = **/f? ]] && print true || print false
> > true
> >> setopt extendedglob
> >> [[ d1/f1 = (*/)#f? ]] && print true || print false
> > true
> >
> > I came across this because it affects the behavior of zmv, via a test
> > that filters filenames (line 254 in zsh5.9). An example:
> >
> >> mkdir d1 d1/d2
> >> touch f0 d1/f1 d1/d2/f2
> >> print -rl -- **/f?
> > d1/d2/f2
> > d1/f1
> > f0
> >> autoload zmv
> >> zmv -n '**/f?' '$f.txt'
> > mv -- d1/d2/f2 d1/d2/f2.txt
> > mv -- d1/f1 d1/f1.txt
> >> zmv -n '(*/)#f?' '$f.txt'
> > mv -- d1/d2/f2 d1/d2/f2.txt
> > mv -- d1/f1 d1/f1.txt
> > mv -- f0 f0.txt
> >
> > I think both zmv calls should have attempted to update the 'f0' file
> > in the base directory. Am I missing something?
> >
> > Thanks,
> > Awk
> >
> I'll leave zmv's implementation for someone else to answer but i suspect the reasoning is similar.
>




Messages sorted by: Reverse Date, Date, Thread, Author