Оператор выбора "case" имеет структуру:
case строка in
шаблон) список команд;;
шаблон) список команд;;
...
esac
Здесь "case" "in" и "esac" - служебные слова. "Строка" (это может быть и один символ) сравнивается с "шаблоном". Затем выполняется "список команд" выбранной строки. Непривычным будет служебное слово "esac", но оно необходимо для завершения структуры.
Пример.
###
# case-1: Структура "case".
# Уже рассматривавшийся в связи со
# структурой "if" пример проще и
# нагляднее можно реализовать с
# помощью структуры "case".
echo -n " А какую оценку получил на экзамене?: "
read z
case $z in
5) echo Молодец ! ;;
4) echo Все равно молодец ! ;;
3) echo Все равно ! ;;
2) echo Все ! ;;
*) echo ! ;;
esac
Непривычно выглядят в конце строк выбора ";;", но написать здесь ";" было бы ошибкой. Для каждой альтернативы может быть выполнено несколько команд. Если эти команды будут записаны в одну строку, то символ ";" будет использоваться как разделитель команд.
Обычно последняя строка выбора имеет шаблон "*", что в структуре "case" означает "любое значение". Эта строка выбирается, если не произошло совпадение значения переменной (здесь $z) ни с одним из ранее записанных шаблонов, ограниченных скобкой ")". Значения просматриваются в порядке записи.
###
# case-2: Справочник.
# Для различных фирм по имени выдается
# название холдинга, в который она входит
case $1 in
ONE|TWO|THREE) echo Холдинг: ZERO ;;
MMM|WWW) echo Холдинг: Not-Net ;;
Hi|Hello|Howdoing) echo Холдинг: Привет! ;;
*) echo Нет такой фирмы ;;
esac
При вызове "case-2 Hello" на экран будет выведено:
Холдинг: Привет!
А при вызове "case-2 HELLO" на экран будет выведено:
Нет такой фирмы
Коль скоро слово "case" переводится как "выбор", то это как бы намек на то, что можно эту структуру использовать для реализации простейших меню.
###
# case-3: Реализация меню с помощью команды "case"
echo "Назовите файл, а затем (через пробел)
наберите цифру, соответствующую требуемой
обработке:
1 - отсортировать
2 - выдать на экран
3 - определить число строк "
read x y # x - имя файла, y - что сделать
case $y in
1) sort >" - перенаправление с добавлением в файл
case $# in
1) cat >> $1 ;;
2) cat >> $2 ${1}_sorted
т.е. последовательно сортируются указанные файлы, результаты сортировки выводятся на печать ("/dev/lp") и направляются в файлы
f1_sorted f2_sorted и f3_sorted
Можно сделать более универсальной команду "lsort", если не фиксировать перечень файлов в команде, а передавать произвольное их число параметрами.
Тогда головная программа будет следующей:
for i
do
proc-sort $i
done
Здесь отсутствие после "i" служебного слова "in" с перечислением имен говорит о том , что список поступает через параметры команды. Результат предыдущего примера можно получить, набрав
lsort f1 f2 f3
Усложним ранее рассматривавшуюся задачу (под именем "case-2") определения холдинга фирмы. Теперь можно при вызове указывать произвольное количество фирм. При отсутствии в структуре оператора "for" фрагмента "in список значений", значения берутся из параметров вызывающей команды.
###
# holding: Справочник.
# Для различных фирм по имени выдается
# название холдинга, в который она входит
for i
do
case $i in
ONE|TWO|THREE) echo Холдинг: ZERO ;;
MMM|WWW) echo Холдинг: Not-Net ;;
Hi|Hello|Howdoing) echo Холдинг: Привет! ;;
*) echo Нет такой фирмы ;;
esac
done
При вызове "holding Hello HELLO ONE" на экране будет:
Холдинг: Привет!
Нет такой фирмы
Холдинг: Not-Net
Еще пример.
###
# subdir: Выдает имена всех поддиректориев
# директория с именем $dir
for i in $dir/*
do
if [ -d $i ]
then echo $i
fi
done
Следующий расчет иллюстрирует полезный, хотя и с долей трюкачества, способ повторения одних и тех же действий несколько раз. Переменныя "i" принимает здесь пять значений: 1, 2, 3, 4, 5, но внутри цикла эта переменная отсутствует и поэтому ее значение никакой роли не играет и ни чего не меняет. С таким же успехом переменная "i" могла принимать значения, скажем ф о к у с , а в результате точно также было бы пять раз повторено одно и то же вычисление содержимого цикла без изменений.
###
# print-5: Организации пятикратного выполнения команды
for i in 1 2 3 4 5
do
cat file-22 > /dev/lp
done
Расчет "print-n" иллюстрирует еще одну полезную возможность в использовании цикла "for". Здесь, после "for i ...", отсутствуют "in ..." и перечень имен, т.е. перечнем имен для "i" становится перечень параметров, а следовательно количество печатаемых экземпляров можно менять.
###
# print-n: Задание числа копий
# через параметры
for i
do
cat file-22 > /dev/lp
done
Смысл не изменится, если первую строку расчета записать как
for i in $*
поскольку значение "$*" - есть список значений параметров.
Отметим различие в специальных переменных "$*" и "$@", представляющих перечень параметров. Первый представляет параметры, как строку, а второй, как совокупность слов.
Пусть командный файл "cmp" имеет вид:
for i in "$*"
do
echo $i
done
echo
for i in "$@"
do
echo $i
done
При вызове
cmp aa bb cc
на экран будет выведено
aa bb cc
aa
bb
cc
case строка in
шаблон) список команд;;
шаблон) список команд;;
...
esac
Здесь "case" "in" и "esac" - служебные слова. "Строка" (это может быть и один символ) сравнивается с "шаблоном". Затем выполняется "список команд" выбранной строки. Непривычным будет служебное слово "esac", но оно необходимо для завершения структуры.
Пример.
###
# case-1: Структура "case".
# Уже рассматривавшийся в связи со
# структурой "if" пример проще и
# нагляднее можно реализовать с
# помощью структуры "case".
echo -n " А какую оценку получил на экзамене?: "
read z
case $z in
5) echo Молодец ! ;;
4) echo Все равно молодец ! ;;
3) echo Все равно ! ;;
2) echo Все ! ;;
*) echo ! ;;
esac
Непривычно выглядят в конце строк выбора ";;", но написать здесь ";" было бы ошибкой. Для каждой альтернативы может быть выполнено несколько команд. Если эти команды будут записаны в одну строку, то символ ";" будет использоваться как разделитель команд.
Обычно последняя строка выбора имеет шаблон "*", что в структуре "case" означает "любое значение". Эта строка выбирается, если не произошло совпадение значения переменной (здесь $z) ни с одним из ранее записанных шаблонов, ограниченных скобкой ")". Значения просматриваются в порядке записи.
###
# case-2: Справочник.
# Для различных фирм по имени выдается
# название холдинга, в который она входит
case $1 in
ONE|TWO|THREE) echo Холдинг: ZERO ;;
MMM|WWW) echo Холдинг: Not-Net ;;
Hi|Hello|Howdoing) echo Холдинг: Привет! ;;
*) echo Нет такой фирмы ;;
esac
При вызове "case-2 Hello" на экран будет выведено:
Холдинг: Привет!
А при вызове "case-2 HELLO" на экран будет выведено:
Нет такой фирмы
Коль скоро слово "case" переводится как "выбор", то это как бы намек на то, что можно эту структуру использовать для реализации простейших меню.
###
# case-3: Реализация меню с помощью команды "case"
echo "Назовите файл, а затем (через пробел)
наберите цифру, соответствующую требуемой
обработке:
1 - отсортировать
2 - выдать на экран
3 - определить число строк "
read x y # x - имя файла, y - что сделать
case $y in
1) sort >" - перенаправление с добавлением в файл
case $# in
1) cat >> $1 ;;
2) cat >> $2 ${1}_sorted
т.е. последовательно сортируются указанные файлы, результаты сортировки выводятся на печать ("/dev/lp") и направляются в файлы
f1_sorted f2_sorted и f3_sorted
Можно сделать более универсальной команду "lsort", если не фиксировать перечень файлов в команде, а передавать произвольное их число параметрами.
Тогда головная программа будет следующей:
for i
do
proc-sort $i
done
Здесь отсутствие после "i" служебного слова "in" с перечислением имен говорит о том , что список поступает через параметры команды. Результат предыдущего примера можно получить, набрав
lsort f1 f2 f3
Усложним ранее рассматривавшуюся задачу (под именем "case-2") определения холдинга фирмы. Теперь можно при вызове указывать произвольное количество фирм. При отсутствии в структуре оператора "for" фрагмента "in список значений", значения берутся из параметров вызывающей команды.
###
# holding: Справочник.
# Для различных фирм по имени выдается
# название холдинга, в который она входит
for i
do
case $i in
ONE|TWO|THREE) echo Холдинг: ZERO ;;
MMM|WWW) echo Холдинг: Not-Net ;;
Hi|Hello|Howdoing) echo Холдинг: Привет! ;;
*) echo Нет такой фирмы ;;
esac
done
При вызове "holding Hello HELLO ONE" на экране будет:
Холдинг: Привет!
Нет такой фирмы
Холдинг: Not-Net
Еще пример.
###
# subdir: Выдает имена всех поддиректориев
# директория с именем $dir
for i in $dir/*
do
if [ -d $i ]
then echo $i
fi
done
Следующий расчет иллюстрирует полезный, хотя и с долей трюкачества, способ повторения одних и тех же действий несколько раз. Переменныя "i" принимает здесь пять значений: 1, 2, 3, 4, 5, но внутри цикла эта переменная отсутствует и поэтому ее значение никакой роли не играет и ни чего не меняет. С таким же успехом переменная "i" могла принимать значения, скажем ф о к у с , а в результате точно также было бы пять раз повторено одно и то же вычисление содержимого цикла без изменений.
###
# print-5: Организации пятикратного выполнения команды
for i in 1 2 3 4 5
do
cat file-22 > /dev/lp
done
Расчет "print-n" иллюстрирует еще одну полезную возможность в использовании цикла "for". Здесь, после "for i ...", отсутствуют "in ..." и перечень имен, т.е. перечнем имен для "i" становится перечень параметров, а следовательно количество печатаемых экземпляров можно менять.
###
# print-n: Задание числа копий
# через параметры
for i
do
cat file-22 > /dev/lp
done
Смысл не изменится, если первую строку расчета записать как
for i in $*
поскольку значение "$*" - есть список значений параметров.
Отметим различие в специальных переменных "$*" и "$@", представляющих перечень параметров. Первый представляет параметры, как строку, а второй, как совокупность слов.
Пусть командный файл "cmp" имеет вид:
for i in "$*"
do
echo $i
done
echo
for i in "$@"
do
echo $i
done
При вызове
cmp aa bb cc
на экран будет выведено
aa bb cc
aa
bb
cc