Arrays (Bash)

Uit De Vliegende Brigade
Naar navigatie springen Naar zoeken springen

In Bash, an array is a one-dimensional sequence of variables.

Introduction

#!/bin/bash

a=(1 2 "Drie" 4 "Vijf")

echo $a        # Returns "1" - First item of the array
echo $a[0]     # Returns "1[0]" - The [0] part is treated as a literal
echo ${a[0]}   # Returns "1"
echo ${a[@]}   # Returns "1 2 3 4" - whole array

Nog een beginnetje:

a[0]="Nul"
a[1]="Eén"

echo $a        # Toont alleen eerste element
echo $a[0]     # Output: Null[0] - Waarschijnlijk niet wat de bedoeling was
echo ${a[1]}   # OK

Multi-dimensional arrays

Bash ondersteunt geen multidimensionale arrays, maar je kunt een heel eind komen middels associative arrays

Associative arrays

Zie Associative arrays (Bash)

Length of an array

E.g.:

Return all indices

${!j[@]} returns all indices. Can be handy as input for a loop. E.g.:

unset j
mapfile -t j < <( wp post list --post_type=product --field=ID --posts_per_page=64 )

echo "Number of items: ${!j[@]}"

Output (some output removed):

Number of items: 0 1 2 3 ... 64 65

Something doesn't add up

Note that there are 64, 65 and/or 66 items, depending on how you ask:

unset j
mapfile -t j < <( wp post list --post_type=product --field=ID --posts_per_page=64 )

echo "Whole array: ${j[@]}"        # 64 IDs
echo "Item 5: ${j[5]}"
echo "All indices: ${!j[@]}"       # 0 to 65 = 66 indices
echo "Number of items: ${#j[@]}"   # 66

Answer: The first two entries contain NULL. Maybe just some unfortunate null space that mapfile couldn't avoid → Indeed. This works better:

unset j
mapfile -t j < <( wp post list --post_type=product --field=ID --posts_per_page=64 | grep . )

echo "Whole array: ${j[@]}"
echo "Item 5: ${j[5]}"
echo "All indices: ${!j[@]}"
echo "Number of items: ${#j[@]}"


Loop through array

Dit werkt. Merk op dat $i de waarde van de cel bevat, niet de index:

array=( one two three )
for i in "${array[@]}"
do
   echo "$i"
done

Loop through the index of an array

Rather than going through the entries of an array, let's loop through its index. Note that this is base 0:

array=( one two three )
for i in "${!array[@]}"
do
   echo "Index: $i - Value: ${array[i]}"
done

Output:

Index: 0 - Value: one
Index: 1 - Value: two
Index: 2 - Value: three

Unset

Use unset to destroy an array. Note that the examples below, exhibit some dubious use of associative arrays:

#1/bin/bash


# Create & fill an array
########################################
#
declare -A tr

echo "Newly declared array: ${tr[@]}"

tr[1,1]="hoi";	tr[1,2]="doei"

echo "Filled array: ${tr[@]}"


# Re-declare doesn't reset
########################################
#
declare -A tr

echo "Array after redeclaring - It doesn't reset the array:"
echo ${tr[@]}


# Unset array
########################################
#
unset tr

echo "Array after unset - Now it's empty: ${tr[@]}"


# Unset a non-existing array
########################################
#
echo "Unsetting a non-existing array doesn't give an error:"
unset ik_besta_niet

Uitvoer:

Newly declared array: 
Filled array: doei hoi
Array after redeclaring - It doesn't reset the array:
doei hoi
Array after unset - Now it's empty: 
Unsetting a non-existing array doesn't give an error:

Reading output of a command into an array

I want to use WP-CLI command wp post list to return IDs of products. I want to store these IDs in an array. Subsequently, I want to use parallelisation to do some nifty stuff with these IDs, without having to wait until tomorrow morning for the results.

This doesn't work:

j=$(wp post list --post_type=product --field=ID --posts_per_page=64)

Eventhough echo ${j[@]} gives a promising result, I think it's just one string and not an array.

This works [1]:

unset j
mapfile -t j < <( wp post list --post_type=product --field=ID --posts_per_page=64 )

echo "Whole array: ${j[@]}"
echo "Item 5: ${j[5]}"

Arithmatic with arrays

This works, so no (()) black magic today. At least, not here:

i=5
echo "Entry i (=5): ${j[$i]}"
echo "Entry i+1: ${j[$i+1]}"
echo "Entry 6: ${j[6]}"

See also

Sources