homogenous
type meaning that all of the ele-
ments stored in the array must be of the same type. But in Bash, with only two types,
strings and integers, an array could store either or both types of values.
As arrays store multiple values, how do you indicate the value you want to access? This is
done through an array
index
. The index is the numeric position in the array of the element.
Like C/C
++
and Java, numbering starts at 0, so the first element is at position 0, the second
element is at position 1, and the nth element is at position n
−
1.
286
◾
Linux with Operating System Concepts
7.7.1 Declaring and Initializing Arrays
Unlike most languages, array variables do not need to be declared in a Bash script. Instead,
you just start using the array. To place values into an array, you can either place individual
values into array locations or you can initialize the entire array. We look at the second
approach first. In these examples, we will use a variable called ARRAY to be our array.
ARRAY
=
(apple banana cherry date)
This assigns ARRAY to have four values. The values are stored in individual array loca-
tions with apple at position 0, banana at position 1, cherry at position 2, and date at posi-
tion 3. Although the above approach is simple, there are several other ways to place values
into the array.
Another way to initialize the array is to use the following notation.
declare –a ARRAY
=
(apple banana cherry date)
In some versions of Linux and Unix, the declaration is required. We will assume it is
not. You can also declare an array using
ARRAY
=
()
. This creates an initially empty array.
The second way to insert values into an array is to place values into individual array
locations. We reference an array location using the notation ARRAY[
i
] where
i
is the posi-
tion. Recall that if our array stores n elements, then
i
will range between 0 and n
−
1. We
can therefore insert the four pieces of fruit into our array using
ARRAY[0]
=
apple
ARRAY[1]
=
banana
ARRAY[2]
=
cherry
ARRAY[3]
=
date
We can also initialize the array using this notation.
ARRAY
=
([0]
=
apple [1]
=
banana [2]
=
cherry [3]
=
date)
You might wonder why this last approach is worthwhile since it is obviously longer and
more typing than using
ARRAY
=
(apple banana cherry date)
. Imagine that you
want to insert values into some locations but not consecutive locations. You want room
to insert other items into positions in between each of these. You could accomplish this
through one of the following approaches. First, we could initialize each array location
individually.
ARRAY[0]
=
apple
ARRAY[2]
=
banana
ARRAY[4]
=
cherry
ARRAY[6]
=
date
Shell Scripting
◾
287
Alternatively, we could combine these assignments into one statement using the follow-
ing notation.
ARRAY
=
([0]
=
apple [2]
=
banana [4]
=
cherry [6]
=
date)
In either case, ARRAY[1], ARRAY[3], and ARRAY[5] are currently empty.
7.7.2 Accessing Array Elements and Entire Arrays
Now that we can insert items into an array, how do we get values out of the array? For
any other variable, the approach is to reference
$variable
. Can we use $ARRAY or
$ARRAY[0] for instance? The answer, unfortunately, is no. To retrieve an item from an
array is slightly more cumbersome. We must wrap the ARRAY[] inside of ${}. Therefore,
to obtain a value from ARRAY, we use
${ARRAY[0]}
and
${ARRAY[1]}
, and so on. To
obtain the ith value in the array, where i is a variable storing an integer number, we use
${ARRAY[i]}
. Notice that we do not precede i with a $.
In most languages, you are not able to inspect an entire array with one instruction. In
Bash, the notation
${array[@]}
will return the entire array as a list. This allows you to
use the array in an iterator for loop much like we saw with the $@ parameter. The notation
${array[*]}
will also return the array as a list. There is a distinction between these two
notations though if you place them in quote marks. Imagine that ARRAY stores (apple
banana cherry date). Then, we see the following behavior:
•
"${ARRAY[@]}"
returns the list (“apple” “banana” “cherry” “date”)
•
"${ARRAY[*]}"
returns the list (“apple banana cherry date”)
So, with @, you receive each array item individually quoted while with *, you receive the
entire array quoted as a single list. You can also obtain the number of elements in the array
through either
${#ARRAY[@]}
or
${#ARRAY[#]}
.
We will typically control access to our array through either a counting for loop or an
iterator for loop. The iterator for loop is easier as there is less code to deal with. For the
counter for loop, we will use
${#ARRAY[@]}
to obtain the number of elements in the loop
and iterate from 0 to
${#ARRAY[@]}-1
. If our loop variable is i, then we access each ele-
ment using
${ARRAY[i]}
.
In summary, we have the following ways to access an array.
•
${array[i]}
—access the ith element of array
•
${array[@]}
—return the entire array as a list
•
${array[*]}
—return the entire array as a list
•
"${array[@]}"
—return the entire array as a list where each item is quoted
•
"${array[*]}"
—return the entire array as a list where the entire list is quoted
288
◾
Linux with Operating System Concepts
•
${#array[@]}
—return the size of the array
•
${#array[*]}
—return the size of the array
Here are two example loops with an array called a:
•
for value in ${a[@]}; do ...$value. . . ; done
•
$value
stores each array value
•
for ((i = 0; i < ${#a[@]}; i++)); do . . .${a[i]}. . . ; done
•
${a[i]}
stores each array value
7.7.3 Example Scripts Using Arrays
Let us take a look at how you might use an array. In the following script, an array of URLs
is presented to the wget program to download each file. We test each file afterward to see if
it worked. The script outputs warning messages for each URL not found.
#!/bin/bash
list
=
(www.nku.edu/ ~ foxr/CIT371/file1.txt
www.uky.edu/cse/welcome.html
www.uc.edu/cs/csce310/hw1.txt
www.xu.edu/welcome.txt www.cs.ul.edu/ ~ wul/music/lyrics.txt)
for i in ${list[@]}; do
wget $i
if [ ! –e $i ]; then
echo Warning, $i not found!
fi
done
What follows is an alternate version of the code. Here, we use the other style of for loop.
Notice here we reference
${#list[@]}
which tells us how many elements are in the array
(four in this case) leading the loop to be:
for ((i
=
0; i
<
4; i
++
)); do
.
#!/bin/bash
list
=
(www.nku.edu/ ~ foxr/CIT371/file1.txt
www.uky.edu/cse/welcome.html
www.uc.edu/cs/csce310/hw1.txt
www.xu.edu/welcome.txt
www.cs.ul.edu/ ~ wul/music/lyrics.txt)
for ((i
=
0; i
<
${#list[@]}; i
++
)); do
url
=
${list[i]}
wget $url
if [ ! –e $url ]; then
echo Warning, $url not found!
fi
done
Shell Scripting
◾
289
As another example, let us consider a script that we wish a set of users to be able to
access. Although we could resolve this through permissions and a special group, we could
also use this approach. The script first defines the legal users in an array. Next, the script
iterates over the array, testing each one against the current user’s USERNAME. Upon a
match, we set isLegal to 1 to indicate that the user is a legal user of the script. After testing
all users in the array, if the user is not legal, they are not allowed to run the script. Notice
that the … is the main portion of the script, omitted here as the code that the script will
execute is immaterial.
#!/bin/bash
legalUsers
=
(foxr zappaf underwoodi dukeg marst)
isLegal
=
0
for user in ${legalUsers[@]}; do
if [ $user
==
$USERNAME ]; then isLegal
=
1; fi
done
if [ $isLegal –eq 1 ]; then
. . .
else echo you are not authorized to run this script!
fi
Finally, we present an example that will monitor specific file modifications. Assume we
have a list of files that we are interested in tracking. We place those file names in an array.
The stat command, among other information, replies with last modification date and time.
Using the option
–c "%Z"
, stat returns the number of seconds since the Epoch (midnight,
January 1, 1970) that the file was last modified. We pass to this shell script the number of
seconds past the Epoch that we are interested in. Any file modified since then will be stored
to a log file.
#!/bin/bash
time
=
$1
files
=
(. . .)
//list the files here
for file in ${files[@]}; do
if [ ‘stat –c%Z $file‘ –lt $time ]; then
echo $file
>>
modified.log; fi
done
As stated earlier, we could similarly accomplish these tasks using a list rather than an
array.
7.8 STRING MANIPULATION
7.8.1 Substrings Revisited
Earlier in the chapter, we examined three string operations: length, index, and substring.
We invoked each of these using the notation
‘expr
Do'stlaringiz bilan baham: |