Manage and use arrays in Shell scripts

botond published 2019. 03. 11., h - 17:08 time

The 1. page content

 

Introductory

During programming, it is often necessary to use arrays, which can be used to store several values ​​at once, which can then be processed automatically in cycles. This is no different for Shell scripts. In this description, we will look at examples of how to use array variables in different situations in our Shell scripts.

 

 

Indexed arrays

Indexed arrays are a simpler type of array. In this type, elements of an array are associated with numeric values, also known as indexes. Indexes are not required in most programming languages, in which case they are created automatically by the interpreter or translator of that particular programming language.

Let's see some examples of their use in the Bash shell scripts.

Declaration, assignment

Indexed arrays do not have to be declared in advance, it is enough to give it only one initial value:

tomb[1]=200

Or for a text value:

tomb[2]="több szavas érték"

The simplest way to check values ​​is the Bash built-in declare command, a -a switch:

declare -a

This command prints all the indexed arrays in the shell namespace, including the one you just created:

[...]
declare -a tomb=([1]="200" [2]="több szavas érték")

Here we can observe that if we give values ​​to an array in this way, these other elements of the array are not affected. That is, if the array previously existed, the previous data will remain in it, only the value of the newly set index will be overwritten. Therefore, when you first use an array, it is a good idea to create it using the parentheses method and immediately populate it with one or more initial values:

tomb=("első érték" "második érték" 3 mégegy)

In this case, the previous content of the array is deleted and the values ​​are added to the array by indexing from 0.

declare -a
[...]
declare -a tomb=([0]="első érték" [1]="második érték" [2]="3" [3]="mégegy")
When assigning values ​​in parentheses, be careful to separate the elements of the array with spaces. If you want to enter a multi-word value, you must enclose it in quotation marks. Numeric values ​​and non-space text values ​​do not need to be enclosed in quotation marks.

And finally, if you just want to smoothly declare an array in which you don't want to place values ​​first, you can do so with one of the following commands:

tomb=()
declare -a tomb=()

At the end of the commands = () assignments ensure that if the array existed before it, empty it.

Read values

For example, we create an array with the previous values:

tomb=("első érték" "második érték" 3 mégegy)

We’ve seen what this looks like in the namespace above, and now let’s read the values ​​one by one based on their indexes:

echo ${tomb[0]}
echo ${tomb[1]}
echo ${tomb[2]}
echo ${tomb[3]}

The output of the commands is as follows:

első érték
második érték
3
mégegy

Thus, we can refer to some elements of the indexed arrays as variables.

Read array properties

During array operations, it is often necessary to read other properties of arrays, such as reading all elements or indexes or number of elements, etc. These properties can be read using special syntaxes, staying in the example array above:

Read all items at once

echo ${tomb[*]}

vagy

echo ${tomb[@]}

Apparently both syntaxs give the same output:

első érték második érték 3 mégegy

Both commands list the values ​​of all the elements in the array one after the other. This is a problem if, as in the example above, we store multi-word values ​​in the array. In this case, when processing the output, we cannot distinguish the boundaries between the elements from the spaces within the elements, so the obtained output becomes useless.

As a solution, we can use one of the following syntaxes instead of the previous one:

echo ${tomb[*]@Q}

vagy

echo ${tomb[@]@Q}

(At first glance, both commands behave the same way)

'első érték' 'második érték' '3' 'mégegy'

In this output, values ​​are wrapped in apostrophes, which we can easily process.

Or, if you want to display the elements of the array specifically for display, you can use the printf command to format the listed data nicely:

printf "'%s' " "${tomb[@]}"
'első érték' 'második érték' '3' 'mégegy'

But we can even display the elements of the array in separate rows without apostrophes:

printf "%s\n" "${tomb[@]}"
első érték
második érték
3
mégegy

And here's the difference between using "*" and "@":

When you expand the array between double quotes, the two syntaxes behave differently:

printf "'%s' " "${tomb[@]}"

We have seen this example before, treating elements of an array as separate words, so each element is placed in separate apostrophes, so multi-word values:

'első érték' 'második érték' '3' 'mégegy'

And for the "*" version:

printf "'%s' " "${tomb[*]}"

It handles all elements of the array in one word, ie wrapping the elements into a single apostrophe pair:

'első érték második érték 3 mégegy'

This is important, for example, when used in cycles.

With these in mind, it is now easier to process array elements. For example, we "catch" a variable (XX = $ (...)), and so on.

Read range

Thanks to the diversity of Bash, it is possible to read some of the arrays with the string cutter solution:

echo ${tomb[@]:2:2}

The command returns 2 elements, starting with element 2 of the array, ie elements 2 and 3 (indexing starts with 0):

3 mégegy

Read all indexes at once

echo ${!tomb[@]}
0 1 2 3

For example, we can work in cycles nicely.

Reads the number of array elements

echo ${#tomb[@]}
4

Reads the length of an array element

The length of the array element with a given index can be read out in characters using the following syntax:

echo ${#tomb[0]}				# 10
echo ${#tomb[1]}				# 13
echo ${#tomb[2]}				# 1
echo ${#tomb[3]}				# 6

 

 

Stitching Arrays

If you want to add more elements to our previous array, you can do so by doing the following:

tomb+=("újabb elem" "mégegy újabb elem")

Then the block if we query it (by the apostrophe method):

printf "'%s' " "${tomb[@]}"

Then it will look like this:

'első érték' 'második érték' '3' 'mégegy' 'újabb elem' 'mégegy újabb elem'

You can also add new elements to the array in the following way:

tomb=("${tomb[@]}" "2000" "következő elem")

The content then:

'első érték' 'második érték' '3' 'mégegy' 'újabb elem' 'mégegy újabb elem' '2000' 'következő elem'

Compared to the previous plus significant appendix, we still have the freedom to determine the position of the elements of the original array in the list, so we can even insert new elements before them.

Using Arrays in Cycles

In this example, we reload our array and then, over a cycle of for, write its index and its associated value to its elements. Our Shell script is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
 
tomb=(
    [0]="első elem"
    [1]="Második elem"
    [2]="Harmadik elem"
    [3]=3
    [4]=negyedik
)
 
 
for i in "${!tomb[@]}"; do
    echo "Index: $i, értéke: ${tomb[$i]}"
done

Here, I created the elements directly with the indexes to make the binding more visible. Also, you can see that it works in multiple lines so that the code is much clearer.

When executed, it gives the following output:

Index: 0, értéke: első elem
Index: 1, értéke: Második elem
Index: 2, értéke: Harmadik elem
Index: 3, értéke: 3
Index: 4, értéke: negyedik
If here in the cycle of "$ {! Arr [@]}" part is replaced by the * solution "$ {! Arr [*]}", it gives a syntax error because it expands the indexes of the array with double quotation marks as one word, which in this case would be "0 1 2 3 4". And such an index cannot be referenced.
So here we can see the difference between the two versions.

So the point is that the loop rotates the array indexes into the loop variable, which we have given: "$ {! Arr [@]}". Then in the cycle we print it out i index followed by the corresponding element of the array referred to as the loop variable.

 

A next page we continue using indexed arrays in junctions.

 

 

Navigation

This description consists of several pages: