Arithmetic Conditionals
Operator |
Meaning |
-lt |
Less than |
-gt |
Greater than |
-le |
Less than or equal to |
-ge |
Greater than or equal to |
-eq |
Equal to |
-ne |
Not equal to |
And as with string comparisons, the arithmetic test returns a result of true or false; 0 if true, 1 otherwise. So, for example, [ 3 -gt 2 ] produces exit status 0, as does [ ( 3 -gt 2 ) || ( 4 -le 1 ) ], but [ ( 3 -gt 2 ) && ( 4 -le 1 ) ] has exit status 1 since the second subexpression isn’t true.
Another way to make arithmetic tests is to use the $((...)) form to encapsulate the condition. For example: [ $(((3 > 2) && (4 <= 1))) = 1 ]. This evaluates the conditionals and then compares the resulting value to 1 (true).
There is an even neater and more efficient way of performing an arithmetic test: by using the ((...)) construct. * This returns an exit status of 0 if the expression is true,and 1 otherwise. The above expression using this construct becomes (( (3 > 2) && (4 <= 1) )). This example returns with an exit status of 1 because, as we said, the second subexpression is false.
cor@debian:~/shell/mar8$ (( (3 > 2) && (4 <= 1) )) cor@debian:~/shell/mar8$ echo $? 1 cor@debian:~/shell/mar8$ (( (3 > 2) && (4 >= 1) ));echo $? 0
Arithmetic Variables and Assignment
Task 6-1 |
Here is a small task that makes use of integer arithmetic. Write a script called ndu that |
Arithmetic for Loops
for (( initialisation ; ending condition ; update )) do statements... done
ending condition tests the variable
for ((;;)) do read var if [ "$var" = "." ]; then break fi done
Arrays
The pushd and popd functions use a string variable to hold a list of directories and manipulate the list with the string pattern-matching operators. Although this is quite efficient for adding or retrieving items at the beginning or end of the string, it becomes cumbersome when attempting to access items that are anywhere else, e.g.,obtaining item N with the getNdirs function. It would be nice to be able to specify the number, or index, of the item and retrieve it. Arrays allow us to do this
An array is like a series of slots that hold values. Each slot is known as an element, and each element can be accessed via a numerical index. An array element can contain a string or a number, and you can use it just like any other variable. The indices for arrays start at 0 and continue up to a very large number. So, for example, the fifth element of array names would be names[4]. Indices can be any valid arithmetic expression that evaluates to a number greater than or equal to 0.
There are several ways to assign values to arrays. The most straightforward way is with an assignment, just like any other variable:
names[2]=alice names[0]=hatter names[1]=duchess
This assigns hatter to element 0, duchess to element 1, and alice to element 2 of the array names.
Another way to assign values is with a compound assignment:
names=([2]=alice [0]=hatter [1]=duchess)
This is equivalent to the first example and is convenient for initializing an array with a set of values. Notice that we didn’t have to specify the indices in numerical order. In fact, we don’t even have to supply the indices if we reorder our values slightly:
names=(hatter duchess alice)
bash automatically assigns the values to consecutive elements starting at 0. If we provide an index at some point in the compound assignment, the values get assigned consecutively from that point on, so:
names=(hatter [5]=duchess alice)
cor@debian:~/shell/mar8$ names=(hatter [5]=duchess alice) cor@debian:~/shell/mar8$ names[0] bash: names[0]: command not found cor@debian:~/shell/mar8$ echo $names[0] hatter[0] cor@debian:~/shell/mar8$ echo ${names[0]} hatter cor@debian:~/shell/mar8$ echo ${names[1]} cor@debian:~/shell/mar8$ echo ${names[5]} duchess cor@debian:~/shell/mar8$ echo ${names[6]} alice cor@debian:~/shell/mar8$ echo ${names[2]} cor@debian:~/shell/mar8$ echo ${names[3]} cor@debian:~/shell/mar8$ echo ${names[4]} cor@debian:~/shell/mar8$ echo ${names[5]} duchess
An element in an array may be referenced with the syntax ${array[i]}. So, from our last example above, the statement echo ${names[5]} would print the string “duchess”. If no index is supplied, array element 0 is assumed.
You can also use the special indices @ and *. These return all of the values in the array and work in the same way as for the positional parameters; when the array reference is within double quotes, using * expands the reference to one word consisting of all the values in the array separated by the first character of the IFS variable, while @ expands the values in the array to separate words. When unquoted, both of them expand the values of the array to separate words. Just as with positional parameters, this is useful for iterating through the values with a for loop:
for i in "${names[@]}"; do echo $i done
Any array elements which are unassigned don’t exist; they default to null strings if you explicitly reference them. Therefore, the previous looping example will print out only the assigned elements in the array names. If there were three values at indexes 1, 45, and 1005, only those three values would be printed. If you want to know what indices currently have values in an array then you can use ${!array[@]}. In the last example this would return 1 45 1005
A useful operator that you can use with arrays is #, the length operator that we saw in Chapter 4. To find out the length of any element in the array, you can use ${#array[i]}. Similarly, to find out how many values there are in the array, use * or @ as the index. So, for names=(hatter [5]=duchess alice), ${#names[5]} has the value 7, and ${#names[@]} has the value 3.