< Previous | Contents | Next >
Accessing Array Elements
So what are arrays good for? Just as many data-management tasks can be performed with a spreadsheet program, many programming tasks can be performed with arrays.
Let’s consider a simple data-gathering and presentation example. We will construct a script that examines the modification times of the files in a specified directory. From this data, our script will output a table showing at what hour of the day the files were last modified. Such a script could be used to determine when a system is most active. This script, called hours, produces this result:
[me@linuxbox ~]$ hours .
Hour | Files | Hour | Files |
---- | ----- | ---- | ----- |
00 | 0 | 12 | 11 |
01 | 1 | 13 | 7 |
02 | 0 | 14 | 1 |
03 | 0 | 15 | 7 |
04 | 1 | 16 | 6 |
05 | 1 | 17 | 5 |
06 | 6 | 18 | 4 |
07 | 3 | 19 | 4 |
08 | 1 | 20 | 1 |
09 | 14 | 21 | 0 |
10 | 2 | 22 | 0 |
11 | 5 | 23 | 0 |
Total files = 80
We execute the hours program, specifying the current directory as the target. It pro- duces a table showing, for each hour of the day (0-23), how many files were last modi- fied. The code to produce this is as follows:
#!/bin/bash
# hours: script to count files by modification time usage () {
echo "usage: ${0##*/} directory" >&2
}
#!/bin/bash
# hours: script to count files by modification time usage () {
echo "usage: ${0##*/} directory" >&2
}
# Check that argument is a directory if [[ ! -d $1 ]]; then
usage exit 1
fi
# Initialize array
for i in {0..23}; do hours[i]=0; done
# Collect data
for i in $(stat -c %y "$1"/* | cut -c 12-13); do j=${i/#0}
((++hours[j])) ((++count))
done
# Display data
echo -e "Hour\tFiles\tHour\tFiles" echo -e "----\t-----\t----\t-----" for i in {0..11}; do
j=$((i + 12))
printf "%02d\t%d\t%02d\t%d\n" $i ${hours[i]} $j ${hours[j]} done
printf "\nTotal files = %d\n" $count
# Check that argument is a directory if [[ ! -d $1 ]]; then
usage exit 1
fi
# Initialize array
for i in {0..23}; do hours[i]=0; done
# Collect data
for i in $(stat -c %y "$1"/* | cut -c 12-13); do j=${i/#0}
((++hours[j])) ((++count))
done
# Display data
echo -e "Hour\tFiles\tHour\tFiles" echo -e "----\t-----\t----\t-----" for i in {0..11}; do
j=$((i + 12))
printf "%02d\t%d\t%02d\t%d\n" $i ${hours[i]} $j ${hours[j]} done
printf "\nTotal files = %d\n" $count
The script consists of one function (usage) and a main body with four sections. In the first section, we check that there is a command line argument and that it is a directory. If it is not, we display the usage message and exit.
The second section initializes the array hours. It does this by assigning each element a value of zero. There is no special requirement to prepare arrays prior to use, but our script needs to ensure that no element is empty. Note the interesting way the loop is con- structed. By employing brace expansion ({0..23}), we are able to easily generate a se- quence of words for the for command.
The next section gathers the data by running the stat program on each file in the direc- tory. We use cut to extract the two-digit hour from the result. Inside the loop, we need to remove leading zeros from the hour field, since the shell will try (and ultimately fail) to interpret values “00” through “09” as octal numbers (see Table 34-2). Next, we increment the value of the array element corresponding with the hour of the day. Finally, we incre- ment a counter (count) to track the total number of files in the directory.
The last section of the script displays the contents of the array. We first output a couple of header lines and then enter a loop that produces four columns of output. Lastly, we output the final tally of files.