For Loops Bash Array Assignment

We cannot imagine a programming language without the concept of arrays. It doesn’t matter how they are implemented among various languages. Instead arrays help us in consolidating data, similar or different, under one symbolic name.

Working With Arrays in Shell Scripting

Here as we are concerned about shell scripting, this article will help you in playing around with some shell scripts which make use of this concept of arrays.

Array Initialization and Usage

With newer versions of bash, it supports one-dimensional arrays. An array can be explicitly declared by the declare shell-builtin.

declare -a var

But it is not necessary to declare array variables as above. We can insert individual elements to array directly as follows.

var[XX]=<value>

where ‘XX’ denotes the array index. To dereference array elements use the curly bracket syntax, i.e.

${var[XX]}

Note: Array indexing always start with 0.

Another convenient way of initializing an entire array is by using the pair of parenthesis as shown below.

var=( element1 element2 element3 . . . elementN )

There is yet another way of assigning values to arrays. This way of initialization is a sub-category of the previously explained method.

array=( [XX]=<value> [XX]=<value> . . . )

We can also read/assign values to array during the execution time using the read shell-builtin.

read -a array

Now upon executing the above statement inside a script, it waits for some input. We need to provide the array elements separated by space (and not carriage return). After entering the values press enter to terminate.

To traverse through the array elements we can also use for loop.

for i in “${array[@]}” do #access each element as $i. . . done

The following script summarizes the contents of this particular section.

#!/bin/bash array1[0]=one array1[1]=1 echo ${array1[0]} echo ${array1[1]} array2=( one two three ) echo ${array2[0]} echo ${array2[2]} array3=( [9]=nine [11]=11 ) echo ${array3[9]} echo ${array3[11]} read -a array4 for i in "${array4[@]}" do echo $i done exit 0

Various Operations on Arrays

Many of the standard string operations work on arrays . Look at the following sample script which implements some operations on arrays (including string operations).

#!/bin/bash array=( apple bat cat dog elephant frog ) #print first element echo ${array[0]} echo ${array:0} #display all elements echo ${array[@]} echo ${array[@]:0} #display all elements except first one echo ${array[@]:1} #display elements in a range echo ${array[@]:1:4} #length of first element echo ${#array[0]} echo ${#array} #number of elements echo ${#array[*]} echo ${#array[@]} #replacing substring echo ${array[@]//a/A} exit 0

Following is the output produced on executing the above script.

apple apple apple bat cat dog elephant frog apple bat cat dog elephant frog bat cat dog elephant frog bat cat dog elephant 5 5 6 6 Apple bAt cAt dog elephAnt frog

I think there is no significance in explaining the above script in detail as it is self-explanatory. If necessary I will dedicate one part in this series exclusively on string manipulations.

Command Substitution with Arrays

Command substitution assigns the output of a command or multiple commands into another context. Here in this context of arrays we can insert the output of commands as individual elements of arrays. Syntax is as follows.

array=( $(command) )

By default the contents in the output of command separated by white spaces are plugged into array as individual elements. The following script list the contents of a directory, which are files with 755 permissions.

#!/bin/bash ERR=27 EXT=0 if [ $# -ne 1 ]; then echo "Usage: $0 <path>" exit $ERR fi if [ ! -d $1 ]; then echo "Directory $1 doesn't exists" exit $ERR fi temp=( $(find $1 -maxdepth 1 -type f) ) for i in "${temp[@]}" do perm=$(ls -l $i) if [ `expr ${perm:0:10} : "-rwxr-xr-x"` -eq 10 ]; then echo ${i##*/} fi done exit $EXT

Simulating Two-dimensional Arrays

We can easily represent a 2-dimensional matrix using a 1-dimensional array. In row major order representation elements in each row of a matrix are progressively stored in array indexes in a sequential manner. For an mXn matrix, formula for the same can be written as.

matrix[i][j]=array[n*i+j]

Look at another sample script for adding 2 matrices and printing the resultant matrix.

#!/bin/bash read -p "Enter the matrix order [mxn] : " t m=${t:0:1} n=${t:2:1} echo "Enter the elements for first matrix" for i in `seq 0 $(($m-1))` do for j in `seq 0 $(($n-1))` do read x[$(($n*$i+$j))] done done echo "Enter the elements for second matrix" for i in `seq 0 $(($m-1))` do for j in `seq 0 $(($n-1))` do read y[$(($n*$i+$j))] z[$(($n*$i+$j))]=$((${x[$(($n*$i+$j))]}+${y[$(($n*$i+$j))]})) done done echo "Matrix after addition is" for i in `seq 0 $(($m-1))` do for j in `seq 0 $(($n-1))` do echo -ne "${z[$(($n*$i+$j))]}\t" done echo -e "\n" done exit 0

Even though there are limitations for implementing arrays inside shell scripting, it becomes useful in a handful of situations, especially when we handle with command substitution. Looking from an administrative point of view, the concept of arrays paved the way for development of many background scripts in GNU/Linux systems.

Share

Pre-requistites

  1. Knowing how to declare an array and set its elements
  2. Knowing how to get the indices of an array
  3. Knowing how to cycle through an array

Setup

This is the same setup as the previous post
Let’s make a shell script. In your favourite editor type

And save it somewhere as . Now we need to make it executable as follows:

Looks good so far.
Let’s declare some arrays:

Goal

Copy the array into another variable such that it is an exact copy of the original.

Iteration 1: Is the array variable a pointer?

Let’s do the obvious thing and see if we can just say

If is a pointer then should give me . This is the output:

is not set, which means that is only the value of the element set at index . This was mentioned in the first post

Iteration 2: Copying array elements with ${original[*]}

Gives us:

At first sight this looks good because all the elements in the first array have been printed. However, has not been printed. That means that the element at is , which is not what we want, obviously.

Trying ${original[@]}

Has the same problem

Iteration 3: Using proper array assignemnt syntax

Notice that is seen as an array because the right hand side of the assignment is a string inside brackets. The problem in the previous iteration is that there is nothing to indicate that is supposed to be an array. Let’s remedy that by adding brackets to the right hand side:

This gives us the following:

Which is exactly what we wanted. This also works with instead of

Why “declare -a” by itself is not enough.

You many have tried this:

Gives us:

Which is the same problems as before. That is because, though copy has been declared as an array, the assignment is in the form such that it is only assigned to the first element. The only way to assign more than one element to more than one index is to use the bracket notation mentioned above.

Breaking Iteration 3: Sparse arrays

Not every array must have serial indices that start from zero. Sometimes the array may be sparse, which means the indices are spread out. Let’s make our array sparse by adding an element at the tenth index and see how our previous method works:

Gives us this:

So it seems that has all the same elements but not at the same index, since has at index 10 but has nothing.

Iteration 4: Copying sparse arrays with indices

To accomplish this we need to know both the elements and their indices. Unfortunately this will require more than one line. It will need a loop:

Gives us the following:

All the elements have been copied and the 10th element is also the same as the original. Mission accomplished.

References

  1. Bash pages
This entry was posted in   Bash Scripting and tagged   arrays, bash, scripting, technical.
Bookmark the   permalink.

0 comments

Leave a Reply

Your email address will not be published. Required fields are marked *