Литмир - Электронная Библиотека
Содержание  
A
A

                write_html_page > $filename

        else

                echo "$PROGNAME: Cannot write file '$filename'" >&2

                exit 1

        fi

else

        write_html_page

fi

У нас уже получился неплохой сценарий, но он еще не закончен. В следующей главе мы добавим в него последнее улучшение.

33. Управление потоком выполнения: цикл for

В этой заключительной главе, посвященной управлению потоком выполнения, мы познакомимся еще с одной конструкцией организации циклов в командной оболочке. Цикл for отличается от циклов while и until поддержкой средств обработки последовательностей. Это очень полезная возможность. Как следствие, цикл for пользуется большой популярностью среди создателей сценариев для bash.

Цикл for реализован, что вполне естественно, в виде команды for. В современных версиях bash поддерживается две формы команды for.

for: традиционная форма

Оригинальный синтаксис команды for имеет следующий вид:

for переменная [in слова]; do

        команды

done

где переменная — это имя переменной, значение которой будет увеличиваться в ходе выполнения цикла, слова — необязательный список элементов, которые последовательно будут присваиваться переменной, и команды — это команды, выполняемые в каждой итерации.

Команду for удобно использовать в командной строке. Рассмотрим, как она работает:

[me@linuxbox ~]$ for i in A B C D; do echo $i; done

A

B

C

D

В этом примере команда for получает список из четырех слов: A, B, C и D. Для обхода этого списка выполняется четыре итерации цикла. В начале каждой итерации переменной i присваивается очередное слово. Внутри цикла находится команда echo, она выводит значение i, чтобы показать, что присваивание действительно выполняется. Так же как в случае с циклами while и until, цикл for заканчивается ключевым словом done.

По-настоящему мощной особенностью for является разнообразие способов формирования списка слов. Например, можно использовать подстановку в фигурных скобках:

[me@linuxbox ~]$ for i in {A..D}; do echo $i; done

A

B

C

D

или подстановку имен файлов:

[me@linuxbox ~]$ for i in distros*.txt; do echo $i; done

distros-by-date.txt

distros-dates.txt

distros-key-names.txt

distros-key-vernums.txt

distros-names.txt

distros.txt

distros-vernums.txt

distros-versions.txt

или подстановку команд:

#!/bin/bash

# longest-word : поиск самой длинной строки в файле

while [[ -n $1 ]]; do

        if [[ -r $1 ]]; then

                max_word=

                max_len=0

                for i in $(strings $1); do

                        len=$(echo $i | wc -c)

                        if (( len > max_len )); then

                                max_len=$len

                                max_word=$i

                        fi

                done

                echo "$1: '$max_word' ($max_len characters)"

        fi

        shift

done

Этот пример осуществляет поиск самой длинной строки в файле. Когда в командной строке указано несколько имен файлов, сценарий вызывает процедуру strings (входит в состав пакета GNU binutils), чтобы получить список «слов» из каждого файла. Цикл for обрабатывает каждое слово по очереди и определяет, является ли оно самым длинным из встречавшихся до сих пор. По завершении цикла сценарий выводит самое длинное слово.

Если необязательный компонент слова в команде for отсутствует, она по умолчанию обрабатывает позиционные параметры. Чтобы показать использование этого способа, изменим сценарий longest-word:

#!/bin/bash

# longest-word2 : поиск самой длинной строки в файле

for i; do

        if [[ -r $i ]]; then

                max_word=

                max_len=0

                for j in $(strings $i); do

                        len=$(echo $j | wc -c)

                        if (( len > max_len )); then

                                max_len=$len

                                max_word=$j

                        fi

                done

                echo "$i: '$max_word' ($max_len characters)"

        fi

done

Почему i?

Вы могли заметить, что во всех примерах цикла for выше использовалась переменная i. Почему? В действительности за этим выбором не стоят какие-то определенные причины, кроме стремления следовать традициям. В команде for можно использовать любую допустимую переменную, но чаще всего используется переменная i, а также j и k.

Своими корнями эта традиция уходит в язык программирования Fortran. В Fortran необъявленные переменные, начинающиеся с букв I, J, K, L и M, автоматически становились целочисленными, тогда как переменные, начинающиеся с любой другой буквы, — действительными, или вещественными (способны хранить числа с дробной частью). Эта особенность вынуждала программистов использовать переменные I, J и K в качестве переменных цикла, так как использование их в качестве временных переменных (чем переменные цикла в действительности и являются) требовало меньших усилий.

Из-за этого даже в среде программистов на Fortran ходила острота: «GOD is real, unless declared integer» (Бог действителен, пока явно не объявлен целым).

Как видите, мы заменили внешний цикл while циклом for. Так как список слов в команде for отсутствует, она перебирает позиционные параметры. Во внутреннем цикле вместо переменной i теперь используется переменная j. Кроме того, нам больше не нужна команда shift.

for: форма в стиле языка C

В некоторые версии bash добавлена вторая форма синтаксиса команды for, напоминающая одноименный оператор в языке программирования C, которая поддерживается также многими другими языками.

for (( выражение1; выражение2; выражение3 )); do

        команды

done

где выражение1, выражение2 и выражение3 — это арифметические выражения, а коман­ды — это команды, выполняемые в каждой итерации цикла.

Своим поведением эта форма эквивалентна следующей конструкции:

(( выражение1 ))

while (( выражение2 )); do

        команды

        (( выражение3 ))

done

выражение1 инициализирует цикл, выражение2 определяет условие завершения цикла, выражение3 выполняется в конце каждой итерации.

Ниже приводится пример типичного применения:

#!/bin/bash

# simple_counter : демонстрация команды for в стиле языка C

for (( i=0; i<5; i=i+1 )); do

        echo $i

done

Этот сценарий произведет следующий вывод:

[me@linuxbox ~]$ simple_counter

0

1

2

3

4

Здесь выражение1 инициализирует переменную i значением 0, выражение2 позволяет продолжать итерации, пока значение i остается меньше 5, выражение3 увеличивает на единицу значение i в конце каждой итерации.

Форма команды for в стиле языка C выглядит предпочтительнее, если требуется работать с числовыми последовательностями. Несколько примеров ее применения будут приведены в следующих двух главах.

Заключительное замечание

Познакомившись с командой for, внесем заключительное усовершенствование в наш сценарий sys_info_page. В настоящий момент функция report_home_space выглядит так:

report_home_space () {

104
{"b":"568756","o":1}