Настройки шрифта

| |

Фон

| | | |

 

#!/bin/bash

# Команда \"continue N\" передает управление в начало внешнего цикла, отстоящего от текущего на N уровней.



for outer in I II III IV V # внешний цикл

do

echo; echo -n \"Группа $outer: \"



for inner in 1 2 3 4 5 6 7 8 9 10 # вложенный цикл

do



if [ \"$inner\" -eq 7 ]

then

continue 2 # Передача управления в начало цикла 2-го уровня.

# попробуйте убрать параметр 2 команды \"continue\"

fi



echo -n \"$inner \" # 8 9 10 никогда не будут напечатаны.

done



done



echo; echo



# Упражнение:

# Подумайте, где реально можно использовать \"continue N\" в сценариях.



exit 0

Пример 10-23. Живой пример использования \"continue N\"

# Albert Reiner привел пример использования \"continue N\":

# ---------------------------------------------------------



# Допустим, у меня есть большое количество задач, обрабатывающие некоторые данные,

#+ которые хранятся в некоторых файлах, с именами, задаваемыми по шаблону,

#+ в заданном каталоге.

#+ Есть несколько машин, которым открыт доступ к этому каталогу

#+ и я хочу распределить обработку информации между машинами.

#+ тогда я обычно для каждой машины пишу нечто подобное:



while true

do

for n in .iso.*

do

[ \"$n\" = \".iso.opts\" ] && continue

beta=${n#.iso.}

[ -r .Iso.$beta ] && continue

[ -r .lock.$beta ] && sleep 10 && continue

lockfile -r0 .lock.$beta || continue

echo -n \"$beta: \" `date`

run-isotherm $beta

date

ls -alF .Iso.$beta

[ -r .Iso.$beta ] && rm -f .lock.$beta

continue 2

done

break

done



# Конкретная реализация цикла, особенно sleep N, зависит от конкретных применений,

#+ но в общем случае он строится по такой схеме:



while true

do

for job in {шаблон}

do

{файл уже обработан или обрабатывается} && continue

{пометить файл как обрабатываемый, обработать, пометить как обработанный}

continue 2

done

break # Или что нибудь подобное `sleep 600\', чтобы избежать завершения.

done



# Этот сценарий завершит работу после того как все данные будут обработаны

#+ (включая данные, которые поступили во время обработки). Использование

#+ соответствующих lock-файлоа позволяет вести обработку на нескольких машинах

#+ одновременно, не производя дублирующих вычислений [которые, в моем случае,

#+ выполняются в течении нескольких часов, так что для меня это очень важно].

#+ Кроме того, поскольку поиск необработанных файлов всегда начинается с

#+ самого начала, можно задавать приоритеты в именах файлов. Конечно, можно

#+ обойтись и без `continue 2\', но тогда придется ввести дополнительную

#+ проверку -- действительно ли был обработан тот или иной файл

#+ (чтобы перейти к поиску следующего необработанного файла).

Конструкция continue N довольно сложна в понимании и применении, поэтому, вероятно лучше будет постараться избегать ее использования.



10.4. Операторы выбора

Инструкции case и select технически не являются циклами, поскольку не предусматривают многократное исполнение блока кода. Однако, они, как и циклы, управляют ходом исполнения программы, в зависимости от начальных или конечных условий.

case (in) / esac

Конструкция case эквивалентна конструкции switch в языке C/C++. Она позволяет выполнять тот или иной участок кода, в зависимости от результатов проверки условий. Она является, своего рода, краткой формой записи большого количества операторов if/then/else и может быть неплохим инструментом при создании разного рода меню.

case \"$variable\" in \"$condition1\" ) command... ;; \"$condition2\" ) command... ;; esac



Заключать переменные в кавычки необязательно, поскольку здесь не производится разбиения на отдельные слова.

 Каждая строка с условием должна завершаться правой (закрывающей) круглой скобкой ).

 Каждый блок команд, отрабатывающих по заданному условию, должен завершаться двумя символами точка-с-запятой ;;.

 Блок case должен завершаться ключевым словом esac (case записанное в обратном порядке).



Пример 10-24. Использование case

#!/bin/bash



echo; echo \"Нажмите клавишу и затем клавишу Return.\"

read Keypress



case \"$Keypress\" in

[a-z] ) echo \"буква в нижнем регистре\";;

[A-Z] ) echo \"Буква в верхнем регистре\";;

[0-9] ) echo \"Цифра\";;

* ) echo \"Знак пунктуации, пробел или что-то другое\";;

esac # Допускается указыватль диапазоны символов в [квадратных скобках].



# Упражнение:

# --------

# Сейчас сценарий считывает нажатую клавишу и завершается.

# Измените его так, чтобы сценарий продолжал отвечать на нажатия клавиш,

# но завершался бы только после ввода символа \"X\".

# Подсказка: заключите все в цикл \"while\".



exit 0

Пример 10-25. Создание меню с помощью case

#!/bin/bash



# Грубый пример базы данных



clear # Очистка экрана



echo \" Список\"

echo \" ------\"

echo \"Выберите интересующую Вас персону:\"

echo

echo \"[E]vans, Roland\"

echo \"[J]ones, Mildred\"

echo \"[S]mith, Julie\"

echo \"[Z]ane, Morris\"

echo



read person



case \"$person\" in

# Обратите внимание: переменная взята в кавычки.



\"E\" | \"e\" )

# Пользователь может ввести как заглавную, так и строчную букву.

echo

echo \"Roland Evans\"

echo \"4321 Floppy Dr.\"

echo \"Hardscrabble, CO 80753\"

echo \"(303) 734-9874\"

echo \"(303) 734-9892 fax\"

echo \"revans@zzy.net\"

echo \"Старый друг и партнер по бизнесу\"

;;

# Обратите внимание: блок кода, анализирующий конкретный выбор, завершается

# двумя символами \"точка-с-запятой\".



\"J\" | \"j\" )

echo

echo \"Mildred Jones\"

echo \"249 E. 7th St., Apt. 19\"

echo \"New York, NY 10009\"

echo \"(212) 533-2814\"

echo \"(212) 533-9972 fax\"

echo \"milliej@loisaida.com\"

echo \"Подружка\"

echo \"День рождения: 11 февраля\"

;;



# Информация о Smith и Zane будет добавлена позднее.



* )

# Выбор по-умолчанию.

# \"Пустой\" ввод тоже обрабатывается здесь.

echo

echo \"Нет данных.\"

;;



esac



echo



# Упражнение:

# --------

# Измените этот сценарий таким образом, чтобы он не завершал работу

#+ после вывода информации о персоне, а переходил на ожидание нового

#+ ввода от пользователя.



exit 0

Очень хороший пример использования case для анализа аргументов, переданных из командной строки.

#! /bin/bash



case \"$1\" in

\"\") echo \"Порядок использования: ${0##*/} <filename>\"; exit 65;; # Параметры командной строки отсутствуют,

# или первый параметр -- \"пустой\".

# Обратите внимание на ${0##*/} это подстановка параметра ${var##pattern}. В результате получается $0.



-*) FILENAME=./$1;; # Если имя файла (аргумент $1) начинается с \"-\",

# то заменить его на ./$1

# тогда параметр не будет восприниматься как ключ команды.



* ) FILENAME=$1;; # В противном случае -- $1.

esac



Пример 10-26. Оператор case допускает использовать подстановку команд вместо анализируемой переменной

#!/bin/bash

# Подстановка команд в \"case\".



case $( arch ) in # команда \"arch\" возвращает строку, описывающую аппаратную апхитектуру.

i386 ) echo \"Машина на базе процессора 80386\";;

i486 ) echo \"Машина на базе процессора 80486\";;

i586 ) echo \"Машина на базе процессора Pentium\";;

i686 ) echo \"Машина на базе процессора Pentium2 или выше\";;

* ) echo \"Машина на другом типе процессора\";;

esac



exit 0

Оператор case допускает использование шаблонных конструкций.

Пример 10-27. Простой пример сравнения строк

#!/bin/bash

# match-string.sh: простое сравнение строк



match_string ()

{

MATCH=0

NOMATCH=90

PARAMS=2 # Функция требует два входных аргумента.

BAD_PARAMS=91



[ $# -eq $PARAMS ] || return $BAD_PARAMS



case \"$1\" in

\"$2\") return $MATCH;;

* ) return $NOMATCH;;

esac



}



a=one

b=two

c=three

d=two



match_string $a # неверное число аргументов

echo $? # 91



match_string $a $b # не равны

echo $? # 90



match_string $b $d # равны

echo $? # 0



exit 0

Пример 10-28. Проверка ввода

#!/bin/bash

# isalpha.sh: Использование \"case\" для анализа строк.



SUCCESS=0

FAILURE=-1



isalpha () # Проверка - является ли первый символ строки символом алфавита.

{

if [ -z \"$1\" ] # Вызов функции без входного аргумента?

then

return $FAILURE

fi



case \"$1\" in

[a-zA-Z]*) return $SUCCESS;; # Первый символ - буква?

* ) return $FAILURE;;

esac

} # Сравните с функцией \"isalpha ()\" в языке C.



isalpha2 () # Проверка - состоит ли вся строка только из символов алфавита.

{

[ $# -eq 1 ] || return $FAILURE