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

Re: A way to find a bug (or explain a missuse of) realpath expansion?



On Thu, May 2, 2024 at 1:06 AM Marc Chantreux <mc@xxxxxxxxxx> wrote:
>
> On Tue, Apr 30, 2024 at 08:43:51PM -0700, Bart Schaefer wrote:
> > > The /usr shade of path will disapear from debian distribution
> > Can you provide a reference for this?  Web search is clogged with
> > reports of accidental deletions of the /usr tree, etc.
>
>         https://lists.debian.org/debian-devel-announce/2023/10/msg00003.html
>         https://wiki.debian.org/UsrMerge

Ah, I must have misunderstood "shade of path will disappear".

> > You're trying to use a glob qualifier form (:A) but you're not doing
> > globbing, you're doing parameter expansion.
>
> I was globing to remove non-existing directories.

What I meant was, syntactically, globbing does not occur in the order
that you think it did here:
  ${(u):-${foo%/}(:A)}
That is, the stuff to the right of :- in that expression is not
globbed until after the entire parameter expansion is resolved, so the
(u) flag does not "see" the result of globbing, it just sees
  /usr/bin /bin(:A)
and does nothing useful with it.

Note also that (:A) has been appended to the entire $foo expansion,
not to each element of the array $foo, so even once you get to the
globbing step only /bin has realpath applied to it -- the result would
be different for the reversed order
  foo=( {,/usr}/bin )

There's no way to embed filename generation (globbing) inside a
${param} expansion without using an intermediate command substitution.
The three $-prefixed forms of expansion -- parameter ${var}, command
$(cmd), and arithmetic $((expr)) -- are processed "together"
left-to-right and inside-out, but the other five -- history, process,
brace, tilde, and globbing -- are strictly independent.  (The
Expansion introduction could be more explicit about this.)

> But let's say it wasn't intentional: don't you think the result is
> flawed anyway? I mean: I don't understand how the same expansion on
> 2 identical elements of the list can lead to 2 different results.

In your attempt to work this out step-by-step you have
  foo=( $foo(:A) )        ; print -l ">>>> realpath" $foo
but there again $foo(:A) is
  /usr/bin /usr/bin /bin /bin(:A)
What you wanted was
  foo=( $^foo(:A) )
to get
  /usr/bin(:A) /usr/bin(:A) /bin(:A) /bin(:A)

Conversely, ${foo:A} is one step (parameter expansion) rather than two
(parameter, then glob) so realpath is "automatically" applied to every
element of the array.

Does that explain it?

You could have removed all the non-existing directories earlier in the
process, like this:
  foo=( {/usr,}/bin{,/}(/N) ) ; print -l ">>>> setting foo" $foo
That attaches the (/N) -- match directories, discard non-matches -- to
the brace expansion, yielding (before globbing)
  /usr/bin(/N) /usr/bin(/N) /bin(/N) /bin(/N)

In fact you could do the entire process right there:
  typeset -aU foo=( {/usr,}/bin{,/}(/N:A) )
  print -l $foo
"Create an array foo of unique elements and assign the realpaths of
the existing directories in the set /usr/bin /bin /usr/bin/ /bin/"

> [...] so the underlining
> question of my precedent mail was: "is the code of zsh easy to dive in"?

I would have to say it's not, at least for what you're trying to
accomplish here.




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