This page has been tested on macOS Catalina and Ubuntu 18.04 & 20.04
‘Arrays’ and ‘lists’ are data types in Bash/Zsh, just like strings, numbers, nulls and Booleans. Fundamentally, they are both collections of elements separated by spaces. Arrays are created using round brackets and lists with quotation marks:
# Arrays
numbers=(2 4 6 8 10)
strings=(
string1
string2
"string 3 with spaces"
string4
)
booleans=(true false false true)
different_data_types=(2 string2 false)
# Lists
numbers='2 4 6 8 10'
strings='
string1
string2
"string 3 with spaces"
string4
'
booleans='true false false true'
different_data_types='2 string2 false'
The difference between them is that arrays are collections of definite, separate elements while lists are actually just strings where the spaces can be used to separate each word into different elements if they are used in the right way.
If we try to use an array as if it were a normal variable, only the first element is accessible:
numbers=(2 4 6 8 10)
echo $numbers
2
If we want to access a specific element, we can index the array. This means we specify exactly which element we are interested in by writing its position in square brackets after the variable’s name. For instance, if we want the element in the second position in the array we can use [2]
:
numbers=(2 4 6 8 10)
echo ${numbers[2]}
6
Remember that Bash/Zsh uses zero-indexing, so the first element is in position zero and the number 6 is actually at index 2, not 3! Notice also that you need to include the curly brackets when making this call; if you leave them out Bash/Zsh will look for a variable called “numbers[2]” instead of a variable called “numbers”.
To use all of the elements, index the variable with the ‘at’ symbol (@
):
numbers=(2 4 6 8 10)
echo ${numbers[@]}
2 4 6 8 10
If you want to use all of the elements individually, which is particularly useful if you want to do different things with each of them, you need to iterate over them in a loop (see below).
Because lists are just strings, they are indexed in the same way as regular stings. The downside to this is that the individual characters (including the spaces) count as separate elements.
list='Alfa Bravo Charlie Delta'
echo ${list:7:10}
avo Charli
A ‘for loop’ takes each element in an array/list in turn and does something with it. To make one, we need the following things:
The logic is: for each element xi in the collection of elements X, do this. Continue iterating over each element until you are done.
# Array
numbers=(2 4 6 8 10)
for number in ${numbers[@]}
do
echo $number
done
2
4
6
8
10
# List
list='2 4 6 8 10'
for element in $list
do
echo "$element"
done
2
4
6
8
10
# Array
strings=(Alfa Bravo Charlie Delta)
for string in ${strings[@]}
do
echo "$string"
done
Alfa
Bravo
Charlie
Delta
# List
list='Alfa Bravo Charlie Delta'
for element in $list
do
echo "$element"
done
Alfa
Bravo
Charlie
Delta
Often it’s useful to repeat a set of commands a specific number of times. This can be achieved using a for loop and an array created directly using curly brackets. For example, to run a set of commands four times:
for i in {1..4}
do
echo $i
done
1
2
3
4
Instead of running a loop for a certain number of times, we can run it until something happens. In the example below, we want to find all the square numbers that are smaller than 100 so we do the following:
The loop will repeat while the square number is less than 100. Once it grows larger than 100 the loop will stop.
# What are the square numbers smaller than 100?
i=1
while [ $(($i**2)) -lt 100 ]
do
echo $(($i**2))
i=$[$i+1] # Increment the loop counter
done
1
4
9
16
25
36
49
64
81
The test for deciding if you want to use a for loop or a while loop is whether you know exactly how many times you will need to run it.
If you run a while loop using a statement that will always be true it will run forever and your script will never stop!
while true
do
echo "This will repeat for all eternity!"
done
Stop this madness by pressing Ctrl+C.
Another way to break out of a while loop is to use the break
command once a certain point is reached. As the name suggests, this command breaks you out of a loop and carries on with the rest of the script. In this example, we have a while loop that will ostensibly run forever because we have set it to run while true
, however, once the square number reaches 100 it will break out and the script will halt:
# What are the square numbers smaller than 100?
i=1
while true
do
if [ $(($i**2)) -gt 99 ]
then
break
fi
echo $(($i**2))
i=$[$i+1] # Increment the loop counter
done
1
4
9
16
25
36
49
64
81
The previous example showed us a way to use a while loop as if it were a for loop, ie to have it run a specific number of times. Here’s an example that will run exactly four times:
i=1
while true
do
echo $i
if [ $i == 4 ]
then
break
fi
i=$[$i+1] # Increment the loop counter
done
1
2
3
4