Arrays (Bash): verschil tussen versies

Uit De Vliegende Brigade
Naar navigatie springen Naar zoeken springen
Regel 135: Regel 135:
 
== Unset ==
 
== Unset ==
  
Use ''unset'' to destroy an array. Note that the examples below, exhibit some dubious use of associative arrays:
+
Use ''unset'' to destroy an array. But do you really need it?
 +
 
 +
Script:
  
 
<pre>
 
<pre>
#1/bin/bash
+
j=(1 2 3 enough)
 
+
echo "Size j: ${#j[@]}"
 
 
# Create & fill an array
 
########################################
 
#
 
declare -A tr
 
  
echo "Newly declared array: ${tr[@]}"
+
j=(5 6)
 +
echo "Size j: ${#j[@]}"
  
tr[1,1]="hoi"; tr[1,2]="doei"
+
unset j
 
+
echo "Size j: ${#j[@]}"
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
 
 
</pre>
 
</pre>
  
Uitvoer:
+
Output:
  
 
<pre>
 
<pre>
Newly declared array:  
+
Size j: 4
Filled array: doei hoi
+
Size j: 2
Array after redeclaring - It doesn't reset the array:
+
Size j: 0
doei hoi
 
Array after unset - Now it's empty:
 
Unsetting a non-existing array doesn't give an error:
 
 
</pre>
 
</pre>
 +
 +
* When you assign again a value to an array, the old values get overwritten - No need to use ''unset''
 +
* After ''unset'', its length is 0
 +
* Might be a good habit to unset an array after use, to free up the memory.
  
 
== Reading output of a command into an array ==
 
== Reading output of a command into an array ==

Versie van 18 okt 2022 17:00

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

No declaration

An array doesn't need to be declared before being used:

j=(1 2 3 blub Blub enough)
echo "Array j: ${j[@]}"

Output:

Array j: 1 2 3 blub Blub enough

Note that the entities are printed on one line.

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 doesn't support multidimensional arrays, but you can get a long way with Associative arrays (Bash).

Associative arrays

An associative array is an array where the index doesn't have to be a number. See Associative arrays (Bash) for more.

Length of an array

E.g.:

echo "Length of array j0: ${#j0[@]}"

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: WP-CLI creates quite some whitespace. 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. But do you really need it?

Script:

j=(1 2 3 enough)
echo "Size j: ${#j[@]}"

j=(5 6)
echo "Size j: ${#j[@]}"

unset j
echo "Size j: ${#j[@]}"

Output:

Size j: 4
Size j: 2
Size j: 0
  • When you assign again a value to an array, the old values get overwritten - No need to use unset
  • After unset, its length is 0
  • Might be a good habit to unset an array after use, to free up the memory.

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 | grep . )

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

With grep . to trim some leading whitespace.

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]}"

Merge arrays

Program:

i1=(1 2 drie vier)
i2=(4 5 blub Blub)
echo "Array i1: ${i1[@]}"
echo "Array i2: ${i2[@]}"

i3=( "${i1[@]}" "${i2[@]}" )
echo "Array i3: ${i3[@]}"

Output:

Array i1: 1 2 drie vier
Array i2: 4 5 blub Blub
Array i3: 1 2 drie vier 4 5 blub Blub

See also

Sources