Arrays

Create an array

Numeric arrays

# creates a global array named buffer
buffer=(a b c)

With the builtin command set

# creates global array named buffer with three values: a, b and c
set -A buffer a b c

With typeset and friends:

# creates a local array buffer
local -a buffer
buffer=(a b c)

Note: If using local, typeset or declare(etc). the array assignment has to be done separately.

# broken
local -a buffer=(a b c) # outputs: zsh: number expected

Using local, typeset or declare without options, make the array local if used inside of functions.

buffer=(a b c)
() { 
  typeset -a buffer
  buffer=(d e f)
}
typeset -p buffer # outputs our first assignment.

You can also convert scalars into arrays

scalar=foo scalar+=(bar)
typeset -p scalar # outputs our new array

Associate arrays

typeset -A buffer
buffer=( key1 val1 key2 val2 )

You can only create associate arrays with typeset/declare/local.

Assignment

Assignment of arrays can be done a few ways

path=( /bin /usr/bin /usr/local/bin ) # assigns 3 elements
path=( /bin /usr/bin )                # redefines path, assigning 2 elements.
path=( /usr/local/bin $path )         # redefines path again, assigning 1 new element and the current elements of $path.

You can insert elements into the array with +=

path+=( ~/bin )
typeset -p path # outputs the new path, with ~/bin as the first element

You can reference individual elements with name[index]=value

path[1]=~/.local/bin      # numerical 
placeholders[foo]=bar     # associate

Arrays can be deleted via unset

unset array1
unset array2 array3 array4 array5

Elements can be deleted like so:

path[1]=()                 # numerical
unset 'placeholders[foo]'  # associate

Using unset on a numeric array sets the element to empty string. Using arr[name]=() will throw an error.

typeset -a arr1; typeset -A arr2
arr1=(foo bar baz) arr2=(abc 123 xyz 456)
printf "${#arr1} - "; unset 'arr1[1]'; print ${#arr1} # the length of the array remained 3
arr2[abc]=()                                          # outputs: zsh: arr2: attempt to set slice of associative array

Array subscripts

Numerical array's subscripts have an arithmetic context, so:

array[2]=string
array[1+1]=string
array[10/5]=string
i=2 array[i]=string 

Are all equivalent.

Create an array with each words of a string

% string="Welcome to the real world, Neo"
% buffer=(${=string})

Create an array of lines from a file

% buffer=("${(f)$(< /etc/hosts)}")
% echo $buffer[1]
127.0.0.1       eva-O1.linagora.com     eva-01

Find element position in array

On numeric arrays, using the subscript flag i performs reverse subscripting and will return the lowermost index that matches the subscript. The subscript is treated as a pattern.

arr=(a b cv de)
echo ${arr[(i)a]}             # this will print "1"
echo ${arr[(i)imnothere]}     # this will print 5, that is (( $#arr + 1 )).
echo ${arr[(i)?]}             # matches index 1 and 2, but prints 1 since it's the lowest.

The subscript flag n can be used together to specify n'th index.

echo ${arr[(in:2:)?]}         # matches index 1 and 2 still, but prints 2 thanks to (n:2:)

You can also search for the highest index with I

arr=(a b cv de)
echo ${arr[(I)?]}             # This will output 2 

Associative variant

For associative arrays, the subscript flags have slightly different meanings, i will use the subscript as a pattern against keys, then print said matching key. The subscript flag r works similarly and test the pattern against values of the associative array and print said value.

So:

typeset -A arr
arr=( foo bar baz qux )
# incorrect: test the keys in $arr for "bar", then print empty string if nothing is found
echo ${arr[(i)bar]}

# also incorrect: tests values, but will print the matching value, not key.
echo ${arr[(r)bar]}

So to print the key of the value like numeric arrays, the parameter expansion flag k can be used together with the subscript flag r to print the key.

# outputs: foo
echo ${(k)arr[(r)bar]}

# outputs: empty string
echo ${(k)arr[(r)imnothere]}

A nice(but rare, i guess) corner case, is the fact that empty string is a valid key in associate arrays.

typeset -A arr
arr=( '' foo bar baz )

# outputs: empty string, which in this array is a key.
echo ${(k)arr[imnothere]}

# outputs: foo
echo $arr[] 

Test if element exist is in an array

A commonly used way of testing if an key is in an array is to use the parameter expansion ${+name} which expands to 0 or 1 depending on if the name is defined or not; with arithmetic expressions, which returns 1 if the results are 0 and returns 0 if the results are non-zero.

arr=( foo bar baz)
(( ${+arr[1]} )) && print defined
(( ${+arr[4]} )) && print defined

This also works as-is with associate arrays.

(( $+functions[_mycmd] )) ||
_mycmd() {
 :
}

The above code is commonly used in completion functions to avoid redefining functions that may already exist.

 
scripting/array.txt · Last modified: 2014/07/02 22:04 by llua