2

I came across a zsh script which contains this parameter expansion

${LBUFFER%%(#m)[_a-zA-Z0-9]#}

For anyone wanting to know the context this expression lives in, its part of a zle widget function that provides vim like abbreviations

Its basic form is obviously a suffix trim. i.e. ${name%%pattern}

i.e. from man zshexpn - PARAMETER EXPANSION

   ${name%pattern}
   ${name%%pattern} 
   If the pattern matches the end of the value of name,  then  sub‐
      stitute the value of name with the matched portion deleted;
     [...]

regarding the parameter expansion flag (#m): from man zshexpn

   #      Evaluate the resulting words as numeric expressions  and    output
      the  characters  corresponding  to  the resulting integer.  Note
      that this form is entirely distinct from use of  the  #  without
      parentheses.


   m      Only  useful together with one of the flags l or r or with the #
      length operator when the MULTIBYTE option is in effect.  Use the
      character  width  reported by the system in calculating how much
      of the string it occupies or the overall length of  the  string.
      Most printable characters have a width of one unit, however cer‐
      tain Asian character sets and certain special effects use  wider
      characters; combining characters have zero width.  Non-printable
      characters are arbitrarily counted as zero width; how they would
      actually be displayed will vary.

regarding the [_a-zA-Z0-9]# part, this is obviously the pattern that gets removed from the end of the LBUFFER string , but is this a regex pattern or some regex globbing hybrid?
Is it part of the zsh-specific "extended_glob" patterns?, i.e. from man zshoptions

   EXTENDED_GLOB
      Treat  the  `#',  `~' and `^' characters as part of patterns for
      filename generation, etc.  (An initial unquoted `~' always  pro‐
      duces named directory expansion.)

what does this zsh parameter expansion do?

2

It seems that is a zsh "extended glob" expression.

i.e. from man zshexpn

Globbing Flags
There are various flags which affect any text to their right up to the end of the enclosing group or to the end of the pattern; they require the EXTENDED_GLOB option. All take the form (#X) where X may have one of the following forms:

[...]
m
Set references to the match data for the entire string matched; this is similar to backreferencing and does not work in filename generation. The flag must be in effect at the end of the pat‐ tern, i.e. not local to a group. The parameters $MATCH, $MBEGIN and $MEND will be set to the string matched and to the indices of the beginning and end of the string, respectively. This is most useful in parameter substitutions, as otherwise the string matched is obvious.

For example,

       arr=(veldt jynx grimps waqf zho buck)
       print ${arr//(#m)[aeiou]/${(U)MATCH}}

forces all the matches (i.e. all vowels) into uppercase, print‐ ing `vEldt jynx grImps wAqf zhO bUck'. Unlike backreferences, there is no speed penalty for using match references, other than the extra substitutions required for the replacement strings in cases such as the example shown.

and the # operator is a so called "closure" or repeated match operator, equivalent to * in regex

as explained here http://zsh.sourceforge.net/Guide/zshguide05.html#l139

so basically, this parameter expansion:

${LBUFFER%%(#m)[_a-zA-Z0-9]#}

will start a regex style backreference starting at (#m) where any pattern matched will be available in a variable $MATCH like \1 in a BRE or $1 in a PCRE.
And because # is just like *, [_a-zA-Z0-9]# will match zero or many characters from the character set [_a-zA-Z0-9].

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.