Arrays (Bash): verschil tussen versies

Uit De Vliegende Brigade
Naar navigatie springen Naar zoeken springen
(47 tussenliggende versies door dezelfde gebruiker niet weergegeven)
Regel 1: Regel 1:
== Beginnetje ==
+
In Bash, an ''array'' is a one-dimensional sequence of variables with an index.
 +
 
 +
== An array has only one dimension ==
 +
 
 +
In Bash, there are no multi-dimensional arrays. You have ''[[Associative arrays (Bash) | associative arrays]]'' which may trick you in believing they are multi-dimensional, but they really aren't.
 +
 
 +
So, an array is pretty much like a vector: A sequence of entities.
 +
 
 +
This article is about these 'normal', 'straight' arrays. Not about associative arrays.
 +
 
 +
== Base zero ==
 +
 
 +
With normal arrays, I don't think you get a say about how the index looks like. It's just an integer sequence, and it starts at ''0'': Bash arrays are ''base zero''.
 +
 
 +
<pre>
 +
j=(1 2 3 blub Blub enough)
 +
echo "Array j: ${j[@]}"
 +
echo "Index j: ${!j[@]}"
 +
</pre>
 +
 
 +
Output:
 +
 
 +
<pre>
 +
Array j: 1 2 3 blub Blub enough
 +
Index j: 0 1 2 3 4 5
 +
</pre>
 +
 
 +
== No declaration ==
 +
 
 +
An array doesn't need to be declared before being used:
 +
 
 +
<pre>
 +
j=(1 2 3 blub Blub enough)
 +
echo "Array j: ${j[@]}"
 +
</pre>
 +
 
 +
Output:
 +
 
 +
<pre>
 +
Array j: 1 2 3 blub Blub enough
 +
</pre>
 +
 
 +
Note that the entities are printed on one line - That might help you to detect variables that may look like arrays, but are just weird multi-line variables, or whatever.
 +
 
 +
== It's called an entry ==
 +
 
 +
The thingy that an array is composed of, seems to be called ''entry''. I'm surprised how many synonyms I know for this word, but when confused, I might just call it an ''entry''.
 +
 
 +
== Assign individual entries ==
 +
 
 +
<pre>
 +
unset j
 +
j[0]="Foo"
 +
j[1]="bar"
 +
 
 +
echo ${j[0]}    # Foo
 +
echo ${j[1]}    # bar
 +
echo ${j[@]}    # Display all entries: Foo bar
 +
echo ${#j[@]}  # Number of entries: 2
 +
echo ${!j[@]}  # Display ll indices: 0 1
 +
</pre>
 +
 
 +
== Assign an array using parenthesis ==
 +
 
 +
OK, it has been demonstrated a couple of time by now, but just for the record:
  
 
<pre>
 
<pre>
#!/bin/bash
+
j=(this is my shiny new array and it has 9 entries)
 +
 
 +
echo "Size: ${#j[@]}"
 +
echo "Content: ${j[@]}"
 +
 
 +
echo "Index Value"
 +
for i in ${!j[@]}
 +
do
 +
  echo "$i: ${j[$i]}"
 +
done
 +
</pre>
 +
 
 +
Output:
 +
 
 +
<pre>
 +
Size: 11
 +
Content: this is my shiny new array and it has 9 entries
 +
Index Value
 +
0: this
 +
1: is
 +
2: my
 +
3: shiny
 +
4: new
 +
5: array
 +
6: and
 +
7: it
 +
8: has
 +
9: 9
 +
10: entries
 +
</pre>
 +
 
 +
Place entries that contain spaces, within double quotes:
 +
 
 +
<pre>
 +
j=("This is the first entry" "This is the second entry")
 +
echo ${#j[@]}
 +
</pre>
 +
 
 +
Output:
 +
 
 +
<pre>
 +
2
 +
</pre>
 +
 
 +
== Index & syntax ==
 +
 
 +
Just some starting stuff:
  
 +
<pre>
 
a=(1 2 "Drie" 4 "Vijf")
 
a=(1 2 "Drie" 4 "Vijf")
  
Regel 11: Regel 122:
 
echo ${a[@]}  # Returns "1 2 3 4" - whole array
 
echo ${a[@]}  # Returns "1 2 3 4" - whole array
 
</pre>
 
</pre>
 
Nog een beginnetje:
 
  
 
<pre>
 
<pre>
Regel 18: Regel 127:
 
a[1]="Eén"
 
a[1]="Eén"
  
echo $a        # Toont alleen eerste element
+
echo $a        # Returns first element
echo $a[0]    # Output: Null[0] - Waarschijnlijk niet wat de bedoeling was
+
echo $a[0]    # Output: Null[0] - Probably not what you wanted?
 
echo ${a[1]}  # OK
 
echo ${a[1]}  # OK
 
</pre>
 
</pre>
 
== Multi-dimensional arrays ==
 
 
Bash ondersteunt geen multidimensionale arrays, maar je kunt een heel eind komen middels ''associative arrays''
 
  
 
== Associative arrays ==
 
== Associative arrays ==
  
Zie [[Associative arrays (Bash)]]
+
An ''associative array'' is an array where the index doesn't have to be a number. I really like them, and I abuse them a lot to make you think they're actually multi-dimensional arrays. See [[Associative arrays (Bash)]] for more.
  
 
== Length of an array ==
 
== Length of an array ==
  
E.g.:
+
<pre>
 +
echo "Length of array j0: ${#j0[@]}"
 +
</pre>
  
 
== Return all indices ==
 
== Return all indices ==
  
<code>${!j[@]}</code> returns all indices. Can be handy as input for a loop. E.g.:
+
<pre>
 +
j=(I never get enough of creating nice arrays. And you?)
 +
echo ${!j[@]}
 +
</pre>
 +
 
 +
Output:
  
 
<pre>
 
<pre>
unset j
+
0 1 2 3 4 5 6 7 8 9
mapfile -t j < <( wp post list --post_type=product --field=ID --posts_per_page=64 )
 
 
 
echo "Number of items: ${!j[@]}"
 
 
</pre>
 
</pre>
  
Output (some output removed):
+
This might come handy for loops:
  
 
<pre>
 
<pre>
Number of items: 0 1 2 3 ... 64 65
+
j=(I never get enough of creating nice arrays. And you?)
 +
echo ${!j[@]}
 +
 
 +
echo "Index Value"
 +
for i in ${!j[@]}
 +
do
 +
  echo "$i: ${j[$i]}"
 +
done
 
</pre>
 
</pre>
  
== Something doesn't add up ==
+
Output:
 
 
Note that there are 64, 65 and/or 66 items, depending on how you ask:
 
  
 
<pre>
 
<pre>
unset j
 
mapfile -t j < <( wp post list --post_type=product --field=ID --posts_per_page=64 )
 
  
echo "Whole array: ${j[@]}"        # 64 IDs
+
0 1 2 3 4 5 6 7 8 9
echo "Item 5: ${j[5]}"
+
Index Value
echo "All indices: ${!j[@]}"      # 0 to 65 = 66 indices
+
0: I
echo "Number of items: ${#j[@]}"  # 66
+
1: never
 +
2: get
 +
3: enough
 +
4: of
 +
5: creating
 +
6: nice
 +
7: arrays.
 +
8: And
 +
9: you?
 
</pre>
 
</pre>
  
Answer: The first two entries contain NULL. Maybe just some unfortunate null space that <code>mapfile</code> couldn't avoid.
+
== Loop through array entries ==
 
 
== Loop through array ==
 
  
 
[https://www.cyberciti.biz/faq/bash-for-loop-array/ Dit] werkt. Merk op dat <code>$i</code> de waarde van de cel bevat, niet de index:
 
[https://www.cyberciti.biz/faq/bash-for-loop-array/ Dit] werkt. Merk op dat <code>$i</code> de waarde van de cel bevat, niet de index:
Regel 80: Regel 198:
 
</pre>
 
</pre>
  
== Loop through the index of an array ==
+
== Loop through array index ==
  
 
Rather than going through the ''entries'' of an array, let's loop through its ''index''. Note that this is ''base 0'':
 
Rather than going through the ''entries'' of an array, let's loop through its ''index''. Note that this is ''base 0'':
Regel 100: Regel 218:
 
</pre>
 
</pre>
  
== Unset ==
+
== Loop through array index - This doesn't work ==
 
 
Use ''unset'' to destroy an array. Note that the examples below, exhibit some dubious use of associative arrays:
 
  
 
<pre>
 
<pre>
#1/bin/bash
+
array_rows=12
  
 +
for i in $array_rows
 +
do
 +
  echo $i
 +
done
 +
</pre>
  
# Create & fill an array
+
The only output will be <code>12</code> - There won't be any loop. So, just giving a number as argument for a loop, doesn't work.
########################################
 
#
 
declare -A tr
 
  
echo "Newly declared array: ${tr[@]}"
+
== Unset ==
  
tr[1,1]="hoi"; tr[1,2]="doei"
+
Use ''unset'' to destroy an array. But do you really need it?
  
echo "Filled array: ${tr[@]}"
+
Script:
  
 +
<pre>
 +
j=(1 2 3 enough)
 +
echo "Size j: ${#j[@]}"
  
# Re-declare doesn't reset
+
j=(5 6)
########################################
+
echo "Size j: ${#j[@]}"
#
 
declare -A tr
 
 
 
echo "Array after redeclaring - It doesn't reset the array:"
 
echo ${tr[@]}
 
  
 
+
unset j
# Unset array
+
echo "Size j: ${#j[@]}"
########################################
 
#
 
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 ==
Regel 171: Regel 276:
 
<pre>
 
<pre>
 
unset j
 
unset j
mapfile -t j < <( wp post list --post_type=product --field=ID --posts_per_page=64 )
+
mapfile -t j < <( wp post list --post_type=product --field=ID --posts_per_page=64 | grep . )
  
 
echo "Whole array: ${j[@]}"
 
echo "Whole array: ${j[@]}"
 
echo "Item 5: ${j[5]}"
 
echo "Item 5: ${j[5]}"
 
</pre>
 
</pre>
 +
 +
With <code>grep .</code> to trim some leading whitespace.
 +
 +
BTW: <code>mapfile</code> really creates an array, and not some kind of multi-line variable or a variable with a lot of spaces & numbers.
  
 
== Arithmatic with arrays ==
 
== Arithmatic with arrays ==
Regel 186: Regel 295:
 
echo "Entry i+1: ${j[$i+1]}"
 
echo "Entry i+1: ${j[$i+1]}"
 
echo "Entry 6: ${j[6]}"
 
echo "Entry 6: ${j[6]}"
 +
</pre>
 +
 +
== Merge arrays ==
 +
 +
<pre>
 +
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[@]}"
 +
</pre>
 +
 +
Output:
 +
 +
<pre>
 +
Array i1: 1 2 drie vier
 +
Array i2: 4 5 blub Blub
 +
Array i3: 1 2 drie vier 4 5 blub Blub
 +
</pre>
 +
 +
== Append ==
 +
 +
''There is more than one way to skin a cat'', especially in Bash. Here are all the different ways that I know of, to append values:
 +
 +
=== Single item using '+=' shorthand operator ===
 +
 +
<pre>
 +
j=(1 2 3 4 enough)
 +
j+=("One more")
 +
echo ${j[@]}
 +
</pre>
 +
 +
Output:
 +
 +
<pre>
 +
1 2 3 4 enough One more
 +
</pre>
 +
 +
=== Another array using '+=' shorthand operator ===
 +
 +
<pre>
 +
j=(1 2 3 4 enough)
 +
k=(3 4 vijf)
 +
 +
j+=("${k[@]}")
 +
echo ${j[@]}
 +
</pre>
 +
 +
Output:
 +
 +
<pre>
 +
1 2 3 4 enough 3 4 vijf
 +
</pre>
 +
 +
=== Single item by index ===
 +
 +
With <code>${#j[@]}</code>, we retrieve the number of entries. This would also be the index for a new entry, as Bash arrays are ''base zero'':
 +
 +
<pre>
 +
j=(1 2 3 4 enough)
 +
echo ${#j[@]}
 +
j[${#j[@]}]="Oops, just one more"
 +
echo ${#j[@]}
 +
echo ${j[@]}
 +
</pre>
 +
 +
Output:
 +
 +
<pre>
 +
5
 +
6
 +
1 2 3 4 enough Oops, just one more
 +
</pre>
 +
 +
=== Single item using parenthesis ===
 +
 +
<pre>
 +
j=(1 2 3 4 enough)
 +
j=(${j[@]} "No! Just one more, please!")
 +
 +
echo ${j[@]}
 +
echo ${#j[@]}
 +
</pre>
 +
 +
Output:
 +
 +
<pre>
 +
1 2 3 4 enough No! Just one more, please!
 +
6
 +
</pre>
 +
 +
=== Multiple item using parenthesis ===
 +
 +
The approach above, can easily be extended to add multiple items:
 +
 +
<pre>
 +
j=(1 2 3 4 enough)
 +
j=(${j[@]} 6 7 8 9 10)
 +
</pre>
 +
 +
But this doesn't work:
 +
 +
<pre>
 +
j=(1 2 3 4 enough)
 +
j=(${j[@]} (6 7 8 9 10))
 +
</pre>
 +
 +
=== Another array using parenthesis ===
 +
 +
This is actually why I wrote this section on appending:
 +
 +
<pre>
 +
j=(1 2 3 4 enough)
 +
k=(blub blub 5 6 7 8 9 10)
 +
j=(${j[@]} ${k[@]})
 +
 +
echo ${j[@]}
 +
echo ${#j[@]}
 +
</pre>
 +
 +
Output:
 +
 +
<pre>
 +
1 2 3 4 enough blub blub 5 6 7 8 9 10
 +
13
 +
</pre>
 +
 +
== Remove an entry ==
 +
 +
<pre>
 +
$ j=(one two three)
 +
$ echo ${#j[@])
 +
3
 +
 +
$ echo ${!j[@]}
 +
0 1 2
 +
 +
 +
$ unset 'j[1]'
 +
$ echo ${j[@]}
 +
one three
 +
 +
$ echo ${#j[@]}
 +
2
 +
 +
# Note that the index is not rebuild - An item is missing:
 +
$ echo ${!j[@]}
 +
0 2
 +
</pre>
 +
 +
== Check for non-existence of an array ==
 +
 +
Including for associative arrays:
 +
 +
<pre>
 +
################################################################################
 +
# Check for empty array
 +
################################################################################
 +
#
 +
unset i
 +
unset j
 +
unset k
 +
declare -gA j
 +
 +
j["foo"]=1
 +
j["bar"]=2
 +
 +
k[1]=1
 +
k[2]=2
 +
 +
if (( ${#i[@]} == 0 )); then
 +
  echo "i is empty"
 +
else
 +
  echo "i is not empty" 
 +
fi
 +
 +
 +
if (( ${#j[@]} == 0 )); then
 +
  echo "j is empty"
 +
else
 +
  echo "j is not empty" 
 +
fi
 +
 +
if (( ${#k[@]} == 0 )); then
 +
  echo "k is empty"
 +
else
 +
  echo "k is not empty" 
 +
fi
 +
</pre>
 +
 +
== Case: Something doesn't add up (2022.10) ==
 +
 +
The output of a WP-CLI command is read into an array. But how long is the array? There seem to be 64, 65 and/or 66 items, depending on how you ask:
 +
 +
<pre>
 +
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
 +
</pre>
 +
 +
Answer: The first two entries contain NULL: WP-CLI creates quite some whitespace. Use <code>grep .</code> to filter out this whitespace:
 +
 +
<pre>
 +
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[@]}"
 
</pre>
 
</pre>
  
Regel 191: Regel 516:
  
 
* [[Associative arrays (Bash)]]
 
* [[Associative arrays (Bash)]]
 +
* [[For-loops (Bash)]]
  
 
== Sources ==
 
== Sources ==
Regel 199: Regel 525:
 
* https://stackoverflow.com/questions/3112687/how-to-iterate-over-associative-arrays-in-bash
 
* https://stackoverflow.com/questions/3112687/how-to-iterate-over-associative-arrays-in-bash
 
* https://stackoverflow.com/questions/11426529/reading-output-of-a-command-into-an-array-in-bash
 
* https://stackoverflow.com/questions/11426529/reading-output-of-a-command-into-an-array-in-bash
 +
* https://linuxhint.com/bash_append_array/
 +
* https://www.usingenglish.com/forum/threads/what-it-that-called-in-english.79248/

Versie van 7 mrt 2023 16:43

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

An array has only one dimension

In Bash, there are no multi-dimensional arrays. You have associative arrays which may trick you in believing they are multi-dimensional, but they really aren't.

So, an array is pretty much like a vector: A sequence of entities.

This article is about these 'normal', 'straight' arrays. Not about associative arrays.

Base zero

With normal arrays, I don't think you get a say about how the index looks like. It's just an integer sequence, and it starts at 0: Bash arrays are base zero.

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

Output:

Array j: 1 2 3 blub Blub enough
Index j: 0 1 2 3 4 5

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 - That might help you to detect variables that may look like arrays, but are just weird multi-line variables, or whatever.

It's called an entry

The thingy that an array is composed of, seems to be called entry. I'm surprised how many synonyms I know for this word, but when confused, I might just call it an entry.

Assign individual entries

unset j
j[0]="Foo"
j[1]="bar"

echo ${j[0]}    # Foo
echo ${j[1]}    # bar
echo ${j[@]}    # Display all entries: Foo bar
echo ${#j[@]}   # Number of entries: 2
echo ${!j[@]}   # Display ll indices: 0 1

Assign an array using parenthesis

OK, it has been demonstrated a couple of time by now, but just for the record:

j=(this is my shiny new array and it has 9 entries)

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

echo "Index 	Value"
for i in ${!j[@]}
do
   echo "$i:	${j[$i]}"
done

Output:

Size: 11
Content: this is my shiny new array and it has 9 entries
Index 	Value
0:	this
1:	is
2:	my
3:	shiny
4:	new
5:	array
6:	and
7:	it
8:	has
9:	9
10:	entries

Place entries that contain spaces, within double quotes:

j=("This is the first entry" "This is the second entry")
echo ${#j[@]}

Output:

2

Index & syntax

Just some starting stuff:

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
a[0]="Nul"
a[1]="Eén"

echo $a        # Returns first element
echo $a[0]     # Output: Null[0] - Probably not what you wanted?
echo ${a[1]}   # OK

Associative arrays

An associative array is an array where the index doesn't have to be a number. I really like them, and I abuse them a lot to make you think they're actually multi-dimensional arrays. See Associative arrays (Bash) for more.

Length of an array

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

Return all indices

j=(I never get enough of creating nice arrays. And you?)
echo ${!j[@]}

Output:

0 1 2 3 4 5 6 7 8 9

This might come handy for loops:

j=(I never get enough of creating nice arrays. And you?)
echo ${!j[@]}

echo "Index 	Value"
for i in ${!j[@]}
do
   echo "$i:	${j[$i]}"
done

Output:


0 1 2 3 4 5 6 7 8 9
Index 	Value
0:	I
1:	never
2:	get
3:	enough
4:	of
5:	creating
6:	nice
7:	arrays.
8:	And
9:	you?

Loop through array entries

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 array index

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

Loop through array index - This doesn't work

array_rows=12

for i in $array_rows
do
   echo $i
done

The only output will be 12 - There won't be any loop. So, just giving a number as argument for a loop, doesn't work.

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.

BTW: mapfile really creates an array, and not some kind of multi-line variable or a variable with a lot of spaces & numbers.

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

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

Append

There is more than one way to skin a cat, especially in Bash. Here are all the different ways that I know of, to append values:

Single item using '+=' shorthand operator

j=(1 2 3 4 enough)
j+=("One more")
echo ${j[@]}

Output:

1 2 3 4 enough One more

Another array using '+=' shorthand operator

j=(1 2 3 4 enough)
k=(3 4 vijf)

j+=("${k[@]}")
echo ${j[@]}

Output:

1 2 3 4 enough 3 4 vijf

Single item by index

With ${#j[@]}, we retrieve the number of entries. This would also be the index for a new entry, as Bash arrays are base zero:

j=(1 2 3 4 enough)
echo ${#j[@]}
j[${#j[@]}]="Oops, just one more"
echo ${#j[@]}
echo ${j[@]}

Output:

5
6
1 2 3 4 enough Oops, just one more

Single item using parenthesis

j=(1 2 3 4 enough)
j=(${j[@]} "No! Just one more, please!")

echo ${j[@]}
echo ${#j[@]}

Output:

1 2 3 4 enough No! Just one more, please!
6

Multiple item using parenthesis

The approach above, can easily be extended to add multiple items:

j=(1 2 3 4 enough)
j=(${j[@]} 6 7 8 9 10)

But this doesn't work:

j=(1 2 3 4 enough)
j=(${j[@]} (6 7 8 9 10))

Another array using parenthesis

This is actually why I wrote this section on appending:

j=(1 2 3 4 enough)
k=(blub blub 5 6 7 8 9 10)
j=(${j[@]} ${k[@]})

echo ${j[@]}
echo ${#j[@]}

Output:

1 2 3 4 enough blub blub 5 6 7 8 9 10
13

Remove an entry

$ j=(one two three)
$ echo ${#j[@])
3

$ echo ${!j[@]}
0 1 2


$ unset 'j[1]'
$ echo ${j[@]}
one three

$ echo ${#j[@]}
2

# Note that the index is not rebuild - An item is missing:
$ echo ${!j[@]}
0 2

Check for non-existence of an array

Including for associative arrays:

################################################################################
# Check for empty array
################################################################################
#
unset i
unset j
unset k
declare -gA j

j["foo"]=1
j["bar"]=2

k[1]=1
k[2]=2

if (( ${#i[@]} == 0 )); then
   echo "i is empty"
else
   echo "i is not empty"   
fi


if (( ${#j[@]} == 0 )); then
   echo "j is empty"
else
   echo "j is not empty"   
fi

if (( ${#k[@]} == 0 )); then
   echo "k is empty"
else
   echo "k is not empty"   
fi

Case: Something doesn't add up (2022.10)

The output of a WP-CLI command is read into an array. But how long is the array? There seem to be 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: WP-CLI creates quite some whitespace. Use grep . to filter out this whitespace:

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

See also

Sources