[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: URL to source file



On 2021-01-27 14:46:14 +0100, Emanuel Berg wrote:
> Vincent Lefevre wrote:
> 
> > With zsh, you can avoid the pipe with zsh expansions:
> >
> >   local ver=${${(M)${(f)"$(aptitude show $pack)"}:#Version:*}#* }
> >
> > or with apt-cache (which is faster than aptitude):
> >
> >   local ver=${${(M)${(f)"$(apt-cache show --no-all-versions
> > $pack)"}:#Version:*}#* }
> 
> Cool :) Thank you!
> 
> However...
> 
> I have a rule not to use code I don't understand,

The zsh parameter expansion syntax is very cryptic (and the above
command is far from being the worst).

> so can you please explain that syntax or provide a URL where it is
> explained? (Or, just a list with names and/or examples should be
> sufficient, actually.)
> 
> The M, f, quotes, colons, and hashes?

Using the "units" example, we start with:

  print -r "$(aptitude show units)"

The double quotes are necessary, as the zshexpn(1) man page says:
for command substitution:

"If the substitution is not enclosed in double quotes, the output
is broken into words using the IFS parameter."

But here, we want to keep the end of lines.

Then one wants to get the "Version:" line, and one can do this via
an array. The "(f)" will turn the aptitude output to an array with
splitting at the end of lines (\n). This can be seen with

  for i in ${(f)"$(aptitude show units)"}; print -r "[$i]"

Without the "(f)", one just gets one element.

The ${name:#pattern} syntax on an array does filtering of elements
matching the pattern. By default, matching array elements are removed.
Here, we want the opposite: to keep the matching array elements. This
is done with the "(M)" flag. Here, the pattern to use is "Version:*",
which matches lines that start with "Version:", the * character
matching any sequence of characters, like in filename generation
(a.k.a. globbing). So,

  print -r ${(M)${(f)"$(aptitude show units)"}:#Version:*}

gives on my machine:

Version: 2.21-1

Then, we want to remove the "Version: " prefix. This is done with
the ${name#pattern} syntax. One could use the "Version: " pattern,
but "* " is shorter and safe since there should be a single space.
Hence

  print -r ${${(M)${(f)"$(aptitude show units)"}:#Version:*}#* }

Note: instead of nested substitutions, one can use intermediate
variables, which can make the code easier to understand.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


Reply to: