seq last
—generate the list of numbers from 1 to
last
by 1
•
seq first last
—generate the list of numbers from
first
to
last
by 1
•
seq first step last
—generate the list of numbers from
first
to
last
by
step
The values of first, last, and step can be literal values such as
seq 1 10
or they can be
values stored in variables, as in
seq $FIRST $LAST
, or they can be values returned from
Linux commands. The result of seq is a list so for instance
seq 5
would return
(1 2 3
4 5)
while
seq 3 10 3
would return
(3 6 9)
.
We can use seq to control a for loop in one of two ways. First, we can store the result of
seq in a variable, such as
LIST
=
‘seq 1 10‘
and then reference the variable in the itera-
tor for loop. Second, we can insert the ‘seq’ instruction in the iterator for loop itself. The
following loop iterates from 1 to 10 by 2, printing each value. This will produce the list of
odd numbers from 1 to 10, printing each on a separate line.
#!/bin/bash
for number in
‘
seq 1 2 10
‘
; do
echo $number
done
If we replace the echo statement with
echo –n "$number"
, we would produce the
list on one line.
7.6.5 Iterating over Files
One of the more common uses of the Bash iterator for loop is to iterate through the files in
a directory. The following example takes each .txt file and examines whether it is writable
or not. If it is writable, its filename is output.
#!/bin/bash
for filename in *.txt; do
if [ -w $filename ];
then echo $filename
fi
done
A more meaningful example is to execute several scripts in a directory. Commonly,
startup scripts are placed into a single directory. We might use a for loop to iterate over the
282
◾
Linux with Operating System Concepts
items in the directory, and if they are regular files, execute them one at a time. We would
not want to execute items that were not regular files (such as directories). The script below
also reports on the number of scripts started.
#!/bin/bash
TOTAL
=
0
for filename in *; do
if [ -f $filename ]; then
./$filename
TOTAL
=
$((TOTAL
+
1))
fi
done
echo $TOTAL scripts started
Let us consider a script to sum up the size of the normal files in a directory. We can
obtain each file’s size in a number of ways, but we will use the du command. We will iterate
through the files in the directory using a for loop and then use an assignment statement
like
TOTAL
=
$((TOTAL
+
‘du $filename‘))
Unfortunately, this will not work because du returns two values, the file size and the file
name. To solve this problem, we can also employ awk.
To simplify the logic, we will divide the computation step into three parts. First, use
du to obtain the file size and name. Second, pipe the result from du to awk where we
will print out the file size. We will take the result of these two combined instructions
and place it into a variable, TEMP. Third, we will add TEMP to TOTAL. The script is as
follows.
#!/bin/bash
for file in *; do
if [ -f $file ]; then
TEMP
=
‘du $file | awk '{print $1}'‘
TOTAL
=
$((TOTAL
+
TEMP))
fi
done
echo Total file size for regular files in ~ is $TOTAL
We need to be careful with the types of operations that we might place inside
‘
‘
marks
in the for loop. Consider the following example.
for filename in ‘ls –l‘; do
if [ -w $filename ]; then . . .
fi
done
Shell Scripting
◾
283
We might think that, as shown earlier, this would iterate through all of the files in the
current directory and perform some operation on the writable files. However, with ls –l, we
do not merely receive a list of filenames. Instead, the long listing of the entire directory is
supplied. Consider this short excerpt of ls –l from the /etc directory:
-rw-r- -r- -. 1 root root 58 Dec 8 2011 networks
-rw-r- -r- -. 1 root root 3390 Dec 7 2011 nfsmount.conf
-rw-r- -r- -. 1 root root 2144 Aug 13 09:51 nscd.conf
As a list, returned from
ls –l
, the for loop would iterate over each of these items. Thus,
the variable, filename, in the above code excerpt takes on each of the following items one
at a time. As most of these are not filenames, the condition,
[ -w $filename ]
, will
yield an error.
-rw-r- -r- -.
1
root
root
58
Dec
8
2011
networks
-rw-r- -r- -.
1
root
root
3390
Dec
7
2011
nfsmount.conf
-rw-r- -r- -.
1
root
root
2144
Aug
13
09:51
nscd.conf
Let us put together everything we have seen about the iterator for loop and write a script,
called
word_match.sh
, to count the number of occurrences of a particular string in a
given file. The script will expect to receive two parameters, a filename and a string. If we
did not get two parameters, or the first parameter is not an existing, regular file, the script
284
◾
Linux with Operating System Concepts
will output an error message. Otherwise, it will use cat to provide a listing of the contents
of the file. A for loop will then iterate over that listing and compare each item (string) to the
second parameter. We will count the number of matches and output a summary at the end.
#!/bin/bash
count
=
0
if [ $# -ne 2 ]; then
echo ERROR, illegal number of parameters
elif [ ! –f $1 ]; then
echo ERROR, $1 is not a regular file
else
for word in ‘cat $1‘; do
if [ $word
==
$2 ];
then count
=
$((count
+
1))
fi
done
echo The number of occurrences of $2 in $1 is $count
fi
You invoke the above script as .
/word_match.sh
Do'stlaringiz bilan baham: |