Чтение онлайн

ЖАНРЫ

Командная строка Linux
Шрифт:

Если необязательный компонент слова в команде 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 {

if [[ $(id -u) -eq 0 ]]; then

cat <<- _EOF_

<H2>Home Space Utilization (All Users)</H2>

<PRE>$(du -sh /home/*)</PRE>

_EOF_

else

cat <<- _EOF_

<H2>Home Space Utilization ($USER)</H2>

<PRE>$(du -sh $HOME)</PRE>

_EOF_

fi

return

}

Теперь мы можем переписать ее, добавив вывод информации о домашнем каталоге каждого пользователя и включив в вывод общее число файлов и подкаталогов в каждом из них:

report_home_space {

local format="%8s%10s%10s\n"

local i dir_list total_files total_dirs total_size user_name

if [[ $(id -u) -eq 0 ]]; then

dir_list=/home/*

user_name="All Users"

else

dir_list=$HOME

user_name=$USER

fi

echo "<H2>Home Space Utilization ($user_name)</H2>"

for i in $dir_list; do

total_files=$(find $i -type f | wc -l)

total_dirs=$(find $i -type d | wc -l)

total_size=$(du -sh $i | cut -f 1)

echo "<H3>$i</H3>"

echo "<PRE>"

printf "$format" "Dirs" "Files" "Size"

printf "$format" "----" "-----" "----"

printf "$format" $total_dirs $total_files $total_size

echo "</PRE>"

done

return

}

В этой новой версии применено многое из того, что мы узнали к данному моменту. Она все еще проверяет наличие привилегий суперпользователя, но вместо того, чтобы выполнить полный набор операций в каждой из ветвей if, здесь устанавливаются некоторые переменные, которые затем используются в цикле for. В функции использованы несколько локальных переменных и команда printf для форматирования части вывода.

Поделиться с друзьями: