2022-04-23 13:26:53 +01:00
|
|
|
---
|
2022-09-06 15:44:40 +01:00
|
|
|
categories:
|
|
|
|
- Programming Languages
|
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
|
|
|
|
2024-02-02 15:58:13 +00: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
|
|
|
|
2024-02-02 15:58:13 +00: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))
|
|
|
|
```
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
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
|
|
|
|
2024-02-02 15:58:13 +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
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
Here we pass all the elements of the array to a
|
|
|
|
[test](/Programming_Languages/Shell/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
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
When you pass an array as an argument to a
|
|
|
|
[function](/Programming_Languages/Shell/Functions_in_Bash.md) it will not
|
|
|
|
immediately be understood to be an array.
|
2023-05-05 10:23:45 +01:00
|
|
|
|
2024-02-02 15:58:13 +00: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
|
|
|
|
2024-02-02 15:58:13 +00: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
|
|
|
|
2024-02-02 15:58:13 +00: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"
|
|
|
|
```
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
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
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
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
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
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
|
|
|
|
```
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
We are leveraging this aspect of Bash when we
|
|
|
|
[loop through each character in a string](/Programming_Languages/Shell/Strings_in_bash.md#loop-through-each-character-in-a-string).
|