Linux. Полное руководство.
8.4. Управляющие структуры.
Напоминаю (п.3.4.7), что список команд — это одиночная команда, конвейер или последовательность команд/конвейеров, разделенных одним из операторов: ; && ||, завершенная точкой с запятой. Не забывайте ставить точку с запятой даже после одиночной команды, терять ее — типичная ошибка начинающих программистов.
В синтаксис следующих команд квадратные скобки не входят: они ограничивают необязательные выражения.
8.4.1. Условные операторы.
Оператор варианта case.
Синтаксис:
Case значение in.
[шаблон1) список1;;
шаблон2 | шаблон3) список2;; ].
Esac.
Ищется первый шаблон, совпадающий со значением. Если он найден, то выполняется соответствующий ему список команд, завершенный двумя символами «;». Шаблон и список разделяются символом «)». Одному списку команд может соответствовать несколько шаблонов, тогда они разделяются символом «|».
В шаблонах могут использоваться метасимволы *, ? и [] (о подстановке метасимволов сказано в п.3.4.5). С их помощью можно организовать инструкцию, действующую как default в операторе switch языка С.
Порядок сравнения шаблонов со значением не определен. Первое совпадение прекращает дальнейшее сравнение и приводит к выполнению соответствующего списка команд и выходу из структуры case — поведение, больше похожее на поведение оператора case в языке Паскаль, чем на switch в языке С.
Листинг 8.1. Пример использования оператора case.
Echo "Ошибка. Кому переслать протокол?".
Echo "Начальнику: b".
Echo "Коллегам: с".
Echo "Сам разберусь: any key".
Read answer.
Case $answer in.
B|B) mail -s "error log" boss < error.log;;
C|C) mail -s 'Help!!! error log' -c ivan den < error.log;;
*) echo "OK. Exiting";
exit;;
Esac.
Обратите внимание на апострофы вместо кавычек во втором списке: они экранируют подстроку «!!» от подстановки предыдущей команды.
Условный оператор if.
Синтаксис:
If список1 then.
список2.
[elif список3 then.
список4].
[else.
список5].
Fi.
Эта конструкция работает так же, как в других языках программирования. Сначала выполняются команды из списка1. Если этот список выполнен успешно, то есть с кодом завершения 0, то выполняется список2, если нет — то список, стоящий после очередного elif. При невозможности выполнить список команд, стоящий после очередного then, выполняется список, стоящий после else.
Можно использовать сокращенный вариант, только if-then-fi:
$ if [ $? -ne 0 ]; then echo "Ошибка. Смотри протокол"; fi;
Оператор test и условные выражения.
В вышеприведенной команде вместо анализа кода завершения списка использована проверка условия. Две формы такой проверки эквивалентны: встроенная команда test и [условие]. Например, для проверки существования файла можно написать.
Test -e <файл>
Или.
[ -е <файл> ].
Если вместо слова test используются квадратные скобки, они обязательно должны быть отделены от аргументов пробелом, потому что на самом деле «[» — это название команды, а «]» — обязательный последний аргумент этой команды.
В случае истинности условия команда test возвращает код успешного завершения, то есть 0; в случае ложности — код ошибки 1 (не спутайте с обычными языками программирования, где 1 — другое имя для true!).
Команда test может проверять и строку на пустоту: непустая строка считается выполнением условия и приводит к коду завершения 0. Пример:
$ test $USER; echo $?
0
$ test $VAR_not_set_yet; echo $?
1
Условные выражения можно комбинировать с помощью обычных логических операций:
♦ !(выражение) — отрицание;
♦ выражение1 -а выражение2 — логическое И (and);
♦ выражение1 -о выражение2 — логическое ИЛИ (or).
Элементарные условные выражения перечислены в таблицах 8.2 и 8.3. Полный список их можно получить по команде help test.
Основные условные выражения для файлов Таблица 8.2.
| Выражение | Истинно, если |
|---|---|
| -d файл | файл существует и является каталогом |
| -е файл | файл существует |
| -f файл | файл существует и является обычным файлом |
| -L файл | файл существует и является символической ссылкой |
| -r файл | файл существует и доступен для чтения |
| -w файл | файл существует и доступен для записи |
| -x файл | файл существует и является исполняемым |
| -s файл | файл существует и его размер больше 0 |
| -N файл | файл существует и изменился со времени последнего чтения |
| файл1 -nt файл2 | время модификации файла1 позже (newer than), чем файла2 |
| файл1 -ot файл2 | время модификации файла1 раньше (older than), чем файла2 |
| файл1 -ef файл2 | файл1 — это жесткая ссылка на файл2 |
Элементарные условные выражение для сравнения строк Таблица 8.3.
| Выражение | Истинно, если |
|---|---|
| -z строка | длина строки равна 0 |
| -n строка | длина строки не равна 0 |
| стр1 == стр2 | строки совпадают |
| стр1 !== стр2 | строки не совпадают |
| стр1 < стр2 | строка1 предшествует строке2 в лексикографическом порядке. Алфавит соответствует текущей локали |
| стр1 > стр2 | строка1 следует за строкой2 в лексикографическом порядке |
Арифметическое условное выражение имеет формат arg1 OP arg2, где arg1 и arg2 — целые числа, a OP — одна из операций:
♦ -eq — равно;
♦ -ne — не равно;
♦ -lt — меньше;
♦ -le — меньше или равно;
♦ -gt — больше;
♦ -ge — больше или равно.
Таким образом, можно переписать предыдущий пример с использованием оператора if:
Листинг 8.2. Пример использования оператора if.
Echo "Ошибка. Кому переслать протокол?".
Echo "Начальнику: b".
Echo "Коллегам: c".
Echo "Сам разберусь; any key".
Read answer.
If [ "$answer" == "b" -o "$answer" == "B" ]; then.
mail -s "error log" boss < error.log;
Elif [ "$answer" == "с" -о "$answer" == "C" ]; then.
mail -s 'Help!!! error log' -c ivan den < error.log;
Else.
echo "OK. Exiting"; exit;
Fi.
8.4.2. Операторы цикла.
Командные интерпретаторы bash и ksh поддерживают циклы типа for, while, until и select, а интерпретатор sh — только циклы for и while.
Оператор цикла с перечислением for.
Синтаксис:
For переменная [in шаблон].
Do.
список.
Done.
В результате подстановки шаблона получается список слов. Переменная получает значение первого слова из этого списка, и выполняется список команд, стоящий между do и done. Затем переменная получает значение очередного слова из списка слов, и снова выполняется список команд. Повторение прекращается по исчерпании слов в списке. Отсутствие конструкции [in шаблон] эквивалентно записи in $@.
Список слов можно сформировать и вручную:
$ for day in Mon Tue Wed Thu Fri; do echo "План работы на $day:"; cat $day.plan; done.
Еще раз напомню, что любой список в bash нужно заканчивать точкой с запятой.
Пример использования цикла с перечислением: допустим, у вас не хочет собираться некий программный пакет — он рассчитывал, что имена заголовочных файлов в некотором каталоге имеют расширение .h, а у вас они такого расширения не имеют (установлена другая версия библиотеки). При этом содержание этих файлов его устраивает. Так создадим символические ссылки, чтобы он нашел заголовки по знакомому имени:
$ cd /путь/к/каталогу/inсludе.
$ for name in *; do ln -s $name $name.h; done.
Оператор цикла с условием while.
Синтаксис:
While список1.
Do.
список2.
Done.
Оператор выполняет список1 и в случае его успешного завершения (нулевого кода возврата) — список2. Процедура повторяется до тех пор, пока результат выполнения списка1 не станет ненулевым. Например:
$ i = 10.
$ while [ $i -gt 0 ]; do.
> echo $i...
> i=${($i-1)).
> done; echo 'BANG!!!'.
$
Примечание. Тот же самый обратный отсчет можно реализовать и с помощью цикла for, если у вас установлена утилита seq, печатающая последовательность (sequence) чисел с заданным шагом: $ for i in `seq 10 -1 0`; do echo $i...; done; echo 'BANG!!!'.Оператор цикла с инверсным условием until.
Синтаксис:
Until список1.
Do.
список2.
Done.
Оператор выполняет список1 и, если он выполнен неуспешно (код возврата ненулевой), то выполняет список2. Процедура повторяется до тех пор, пока результат выполнения списка1 не станет нулевым.
Оператор цикла с выбором select.
Синтаксис:
Select переменная [in шаблон].
Do.
список.
Done.
В результате подстановки шаблона получается список слов. К этим словам оператор добавляет порядковые номера и выводит весь набор в стандартный поток ошибок (stderr). Если шаблон опущен, то вместо него используется список позиционных параметров. После этого оболочка выводит приглашение и считывает строку из стандартного потока ввода (stdin). Если строка содержит номер, соответствующий какому-либо слову из списка, то переменная получает это слово в качестве значения. Если в строке подходящего номера нет, то значением переменной становится пустая строка. После этого выполняется список команд, и процедура повторяется до тех пор, пока в строке ввода не встретится символ конца файла (введите Ctrl+D) или пока в списке команд не встретится команда break или return.
Этот оператор полезен для создания нумерованных пунктов меню. Например, у меня в каталоге ~/temp есть три файла: proto.txt, file.txt и README. В листинге 8.3. приведен фрагмент сценария, позволяющего быстро просмотреть любой из них.
Листинг 8.3. Пример использования оператора select.
Echo "Выберите файл для просмотра:".
Select file in ~/temp/* Quit;
Do.
if [ -f $file ]; then cat $file;
else break;
fi.
Done.
Запустив этот сценарий, я увижу на экране:
Выберите файл для просмотра:
1) /home/den/temp/file.txt.
2) /home/den/temp/proto.txt.
3) /home/den/temp/README.
4) Quit.
#?
Последняя строка — это приглашение, устанавливаемое переменной окружения PS3.
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
- 340.
- 341.
- 342.
- 343.
- 344.
- 345.
- 346.
- 347.
- 348.
- 349.
- 350.
- 351.
- 352.
- 353.
- 354.
- 355.
- 356.
- 357.
- 358.
- 359.
- 360.
- 361.
- 362.
- 363.
- 364.
- 365.
- 366.
- 367.
- 368.
- 369.
- 370.
- 371.
- 372.
- 373.
- 374.
- 375.
- 376.
- 377.
- 378.
- 379.
- 380.
- 381.
- 382.
- 383.
- 384.
- 385.
- 386.
- 387.
- 388.
- 389.
- 390.
- 391.
- 392.
- 393.
- 394.
- 395.
- 396.
- 397.
- 398.
- 399.
- 400.
- 401.
- 402.
- 403.
- 404.
- 405.
- 406.
- 407.
- 408.
- 409.
- 410.
- 411.
- 412.
- 413.
- 414.
- 415.
- 416.
- 417.
- 418.
- 419.
- 420.
- 421.
- 422.
- 423.
- 424.
- 425.
- 426.
- 427.
- 428.
- 429.
- 430.
- 431.
- 432.
- 433.
- 434.
- 435.
- 436.
- 437.
- 438.
- 439.
- 440.
- 441.
- 442.
- 443.
- 444.
- 445.
- 446.
- 447.
- 448.
- 449.
- 450.
- 451.
- 452.
- 453.
- 454.
- 455.
- 456.
- 457.
- 458.
- 459.
- 460.
- 461.
- 462.
- 463.
- 464.
- 465.
- 466.
- 467.
- 468.
- 469.
- 470.
- 471.