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 <vinc...@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)