Search code examples
parameterszsh

'zsh array parameters' in the manual I can NOT fully understand. Can anyone explain this by giving examples?


The only one I could understand was "$FOO[2,5]". but r, R,s, w options I don't know clearly how to use them in the real problems:

'zsh' site says: (http://zsh.sourceforge.net/Doc/Release/Parameters.html#Parameters)

Array Parameters

The value of an array parameter may be assigned by writing:

name=(value ...) ...

Individual elements of an array may be selected using a subscript. A subscript of the form [exp] selects the single element exp, where exp is an arithmetic expression which will be subject to arithmetic expansion as if it were surrounded by $((...)). The elements are numbered beginning with 1 unless the KSH_ARRAYS option is set when they are numbered from zero.

A subscript of the form [] or [@] evaluates to all elements of an array; there is no difference between the two except when they appear within double quotes. "$foo[]" evaluates to "$foo[1] $foo[2] ...", while "$foo[@]" evaluates to "$foo[1]" "$foo[2]", etc.

A subscript of the form [exp1,exp2] selects all elements in the range exp1 to exp2, inclusive. If one of the subscripts evaluates to a negative number, say -n, then the n'th element from the end of the array is used. Thus $foo[-3] is the third element from the end of the array foo, and $foo[1,-1] is the same as $foo[*].

Subscripting may also be performed on non-array values, in which case the subscripts specify a substring to be extracted. For example, if FOO is set to foobar, then echo $FOO[2,5] prints ooba.

Subscripts may be used inside braces used to delimit a parameter name, thus ${foo[2]} is equivalent to $foo[2]. If the KSH_ARRAYS option is set, the braced form is the only one that will work, the subscript otherwise not being treated specially.

If a subscript is used on the left side of an assignment the selected range is replaced by the expression on the right side.

If the opening bracket or the comma is directly followed by an opening parenthesis the string up to the matching closing parenthesis is considered to be a list of flags. The flags currently understood are:

e This option has no effect and retained for backward compatibility only. w If the parameter subscripted is a scalar, then this flag makes subscription work on a per-word basis instead of characters. s:string: Defines the string that separates words (for use with the w flag). p Recognize the same escape sequences as the print builtin in the string argument of a subsequent s flag. f If the parameter subscripted is a scalar than this flag makes subscription work on a per-line basis instead of characters. This is a shorthand for pws:\n:. r If this flag is given the exp is taken as a pattern and the result is the first matching array element, substring or word (if the parameter is an array, if it is a scalar, or if it is a scalar and the w flag is given, respectively); note that this is like giving a number: $foo[(r)??,3] and $foo[(r)??,(r)f*] work. R Like r, but gives the last match. i Like r, but gives the index of the match instead; this may not be combined with a second argument. I Like i, but gives the index of the last match. n:expr: If combined with r, R, i, or I, makes them return the n'th or n'th last match (if expr evaluates to n).


Solution

  • Not sure where you are quoting from, as that text does not appear on the page you linked. Here's some examples of those flags in action:

    # If the parameter subscripted is a scalar
    foo="The quick brown fox jumps over the lazy dog"
    echo $foo[2]
    # => h       (the second character)
    echo $foo[(w)2]
    # => quick   (the second word)
    echo $foo[(ws:fox:)2]
    # =>  jumps over the lazy dog    (the second "word", but delimited by "fox", not space)
    echo $foo[(wr)*az*]
    # => lazy    (the first word that matches the pattern "*az*")
    echo $foo[(wR)?????]
    # => jumps   (the last word that matches the pattern "?????")
    echo $foo[(wrn.2.)???]
    # => fox     (the second three-letter word)
    echo $foo[(wrin.2.)???]
    # => 17      (the index of second three-letter word)
    
    # If the parameter subscripted is an array
    foo=("The quick brown fox" jumps "over the lazy dog")
    echo $foo[1]
    # => The quick brown fox    (The first element)
    echo $foo[(r)*the*dog]
    # => over the lazy dog      (The first element that matches the pattern "*the*dog")
    

    For a bit more real problem, assume I have a file .pass that contains

    DB_NAME=mydb
    DB_USER=me
    DB_PASS=not real password
    DB_HOST=localhost
    DB_PORT=5432
    

    Then, this will read in your password without using external utilities like grep, sed or awk:

    file=$(<.pass)                # read in the file contents
    line=$file[(fr)DB_PASS=*]     # find the line (f) that matches pattern (r)
    pass=$line[(ws:=:)2]          # get the second (2) segment (w) split by "=" (s:=:)