eolas/zk/Lists_and_arrays.md

165 lines
3.9 KiB
Markdown
Raw Normal View History

2022-04-23 13:26:53 +01:00
---
tags:
- shell
2023-02-21 07:34:13 +00:00
- data-structures
2022-04-23 13:26:53 +01:00
---
2023-02-26 11:56:30 +00:00
# Arrays in Bash
2022-04-23 13:26:53 +01:00
We define an array as follows:
2022-09-06 15:44:40 +01:00
```bash
2022-04-23 13:26:53 +01:00
words=(here are some words)
2022-09-06 15:44:40 +01:00
```
2022-04-23 13:26:53 +01:00
We can also explicitly define an array using `declare` :
2022-09-06 15:44:40 +01:00
```bash
2022-04-23 13:26:53 +01:00
declare -a words=("element1" "element2" "element3")
2022-09-06 15:44:40 +01:00
```
2022-04-23 13:26:53 +01:00
2023-02-26 11:56:30 +00:00
## Index notation
2022-04-23 13:26:53 +01:00
We access specific array elements by their index using the same braces style we
use with variables:
2022-04-23 13:26:53 +01:00
2022-09-06 15:44:40 +01:00
```bash
2023-02-26 11:56:30 +00:00
echo "${words[2]}"
2022-04-23 13:26:53 +01:00
# element3
2022-09-06 15:44:40 +01:00
```
2022-04-23 13:26:53 +01:00
2023-02-26 11:56:30 +00:00
## Iterating through arrays
2022-04-23 13:26:53 +01:00
2022-09-06 15:44:40 +01:00
```bash
2022-04-23 13:26:53 +01:00
for i in "${words[@]}"
do
echo "$i"
# or do whatever with individual element of the array
done
# element1 element2 element3
2022-09-06 15:44:40 +01:00
```
2022-04-23 13:26:53 +01:00
Note that `@` here is a special symbol standing for all the members of the
`words` array.
2022-04-23 13:26:53 +01:00
2023-02-26 11:56:30 +00:00
## Sorting arrays
2023-02-07 08:44:16 +00:00
2023-02-26 11:56:30 +00:00
### Sorting an integer array highests to lowest
2023-02-07 08:44:16 +00:00
```bash
sorted_array=($(echo "${array[@]}" | tr " " "\n" | sort -nr))
```
Where `array` is the name of the original array. The sorted array will be stored
in the `sorted_array` array.
2023-02-07 08:44:16 +00:00
The `sort` command sorts the input in reverse numerical order (`-n` for
numerical sort and `-r` for reverse sort). The `tr` command is used to convert
the spaces in the array to newline characters so that each element is sorted on
a separate line.
2023-02-07 08:44:16 +00:00
2023-02-26 11:56:30 +00:00
## Pushing, appending to an array
We use the `+=` shorthand to add elements to a preexisting array:
```bash
preExistingArray=(1 2 3)
preExistingArray+=(4)
echo preExistingArray
# 1 2 3 4
```
> Note that we have to put the item we want to addend within array brackets
2023-05-05 10:23:45 +01:00
## Check if array empty
2022-04-23 13:26:53 +01:00
2023-05-05 10:23:45 +01:00
```sh
an_array=()
2022-04-23 13:26:53 +01:00
2023-05-05 10:23:45 +01:00
if [ -z "${another_array[@]}" ]; then
echo "Array is empty"
else
echo "Array is not empty"
fi
2022-09-06 15:44:40 +01:00
```
2023-02-21 07:34:13 +00:00
Here we pass all the elements of the array to a
2024-02-17 11:57:44 +00:00
[test](Test_values_in_Bash.md) condition which
tests for an empty string.
2023-05-05 10:23:45 +01:00
> NB: This will not immediately work in the context of a function. See below.
## Weirdness with functions
When you pass an array as an argument to a
2024-02-17 11:57:44 +00:00
[function](Functions_in_Bash.md) it will not
immediately be understood to be an array.
2023-05-05 10:23:45 +01:00
When we use `$1` to individuate the first function argument this is read as
string. So if you parsed an array argument as `$1`, any logic you have in the
function will work on the assumption that the argument is a string, not an
array.
2023-05-05 10:23:45 +01:00
To get round this we have to effectively _redeclare_ the argument as an array
before running any array logic. We do this through a **nameref** (a reference to
a variable). The nameref resolves to the value of the variable it references.
This allows you to indirectly manipulate the value of the original variable
through the nameref.
2023-05-05 10:23:45 +01:00
A nameref is created with the `-n` flag. The following function uses this method
to check if an array is empty:
2023-05-05 10:23:45 +01:00
```sh
function array_empty() {
declare -n arr=$1
if [ ${#arr[@]} -gt 0 ]; then
echo "array is not empty"
else
echo "array is empty"
fi
}
my_array=()
array_empty "my_array"
```
You'll notice when we invoke the function we pass the array as a string, this
facilitates the nameref operation in the function.
2023-05-05 10:23:45 +01:00
2023-02-21 07:34:13 +00:00
## Associational arrays / maps
With Bash 4 we gained an additional array-like data structure that is key-value
based and similar to maps in other languages.
2023-02-21 07:34:13 +00:00
```bash
declare -A rock=(["win"]="scissors" ["lose"]="paper")
```
We would then individuate a value with `"${rock[win]}"`
2023-02-26 11:56:30 +00:00
## Lists as implicit string arrays
When we use the term **list** in bash, we are not actually referring to a
specific type of data structure. Instead a **list variable** is really just a
normal variable wrapped in quote marks that has strings separated by spaces.
Despite the fact that this is not an actual iterative data structure, we are
still able to loop through variables of this type.
2023-02-26 11:56:30 +00:00
```bash
A_STR_LIST="cat dog hamster"
AN_INT_LIST="1 2 3"
```
To iterate through a list variable, we can use a for loop:
```bash
for ele in $A_STR_LIST; do
echo $ele
done
```
We are leveraging this aspect of Bash when we
2024-02-17 11:57:44 +00:00
[loop through each character in a string](Strings_in_bash.md#loop-through-each-character-in-a-string).