Learning_the_bash_Shell_Third_Edition 13/n

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
prints a summary of the disk space usage for each directory argument (and any subdirec-
tories), both in terms of bytes, and kilobytes or megabytes (whichever is appropriate).

 

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.

 

  

 

posted @ 2021-03-08 13:34  碧水东流至此回  阅读(48)  评论(0编辑  收藏  举报