Shell позволяет структурировать условные переходы с помощью оператора if. Простейшая форма оператора if следующая:
if список команд
then список команд
fi
Список команд, стоящий после if, выполняется, и если код завершения последней выполненной команды равен 0, тогда выполняется список команд, указанный после then. Слово fi обозначает конец команды if.
Чтобы выполнить альтернативный набор команд при ненулевом коде завершения, используется условие else, которое записывается cледующим образом:
if список команд
then список команд
else список команд
fi
Используя условие elif вместе с командой if, можно выполнять различные условия, но при большом количестве проверок предпочтительнее использовать оператор case. Например:
if test -f "$1"
# является ли $1 файлом?
then pr $1
elif test -d "$1"
# если нет, то является ли $1 каталогом?
then (cd $1; pr *)
else echo $1 не является ни файлом, ни каталогом
fi
Приведенный пример выполняется следующим образом: если значение первого позиционного параметра является именем файла (-f), то этот файл печатается; если нет, то проверяется, является ли это имя именем каталога (-d). Если это так, то вы переходите в этот каталог (cd) и печатаете все находящиеся в нем файлы ( pr *). Во всех остальных случаях появляется сообщение об ошибке.
Команды if могут вкладываться друг в друга, но каждый if обязательно должен иметь свой fi.
Кодом завершения команды if является код завершения последней выполненной команды после условий then и else. Если команды не выполнялись, то код завершения равен 0.
Обратите внимание, что вместо указания команды test можно использовать альтернативное обозначение - прямоугольные скобки с заключенным в них проверяемым выражением. Например, предыдущий пример можно было записать так:
if [ -f "$1" ]
# является ли $1 файлом?
then pr $1
elif [ -d "$1" ]
# если нет, то является ли $1 каталогом?
then (cd $1; pr *)
else echo $1 не является ни файлом, ни каталогом
fi
Обратите внимание на то, что при такой форме записи пробелы после левой скобки и перед правой обязательны.
Оператор case также дает возможность проверять различные условия. Основной формат оператора case следующий:
case подстрока in
шаблон ) cписок команд ;;
....
шаблон ) cписок команд ;;
esac
Shell пытается найти указанную подстроку по очереди в каждом шаблоне, используя те же самые соглашения, что и при генерации имен файлов. Если соответствие установлено, то выполняется список команд после этого шаблона. Два символа точки с запятой (;;) служат обозначением конца оператора case и необходимы после каждого шаблона кроме последнего. Обратите внимание на то, что только одно значение шаблона (из указанных) может обнаружиться в подстроке, что сравнение с шаблонами выполняется последовательно, и поэтому если первым шаблоном выступает звездочка (*), все остальные игнорируются.
С одним и тем же списком команд может быть связано несколько альтернативных шаблонов, разделенных символом (|).
case $i in
*.c) cc $i
;;
*.h | *.sh)
: do nothing
;;
*) echo "$i of unknown type"
;;
esac
В этом примере для второго набора шаблонов не выполняется ни каких действий, т.к. указана пустая команда (:). Звездочка используется как шаблон, соответствующий любому слову.
Код завершения оператора case равен коду завершения последней выполненной команды. Если никакие команды не выполнялись, то код завершения равен 0.
Условные циклы: while и until
Основная форма команды while имеет вид:
while список команд
do
список команд
done
Сначала выполняются команды из первого списка, и если код завершения последней команды в этом списке равен 0, тогда выполняются команды из второго списка. Эта последовательность повторяется до тех пор, пока код завершения первого списка равен 0. Чтобы цикл выполнялся до тех пор, пока код завершения первого списка не равен 0, надо заменить while на until.
Любая строка может быть заменена символом "точка с запятой". Код завершения команд while и until равен коду завершения последней выполненной команды во втором списке. Если команды из второго списка не выполнялись, код завершения равен 0.
Организация цикла для списка: for
Часто бывает нужно выполнить некоторый набор операций для каждого файла из какого-либо списка или выполнить одну команду для каждого из нескольких аргументов. Для этого существует команда for. Формат команды for следующий:
for переменная in список значений
do
список команд
done
Значения переменных в списке разделяются пробелами. Команды в списке команд выполняются один раз для каждого значения переменной из списка значений. Переменной по очереди присваивается каждое значение из списка. Например, следующий цикл for производит сравнение исходных текстов xec.c, cmd.c и word.c в текущем каталоге с файлами с такими же именами, но в каталоге
/usr/src/cmd/sh:
for CFILE in xec cmd word
do
diff $CFILE.c /usr/src/cmd/sh/$CFILE.c
done
Обратите внимание на то, что первое упоминание имени CFILE сразу после слова for не сопровождается появлением символа "$", поскольку в данном случае используется имя переменной, но не ее значение.
Слово "in", являющееся частью команды for, можно не указывать. В этом случае текущий набор позиционных параметров будет использован вместо списка значений. Это полезно в том случае, если набор команд выполняется для каждого аргумента из списка аргументов, общее число которых неизвестно.
В качестве примера создайте файл с именем echo2, который содержит следующий текст:
Для прекращения выполнения циклов while или for применяется команда break. Команда continue немедленно запускает выполнение следующего шага в цикле. Эти команды действуют только если они встречаются между командами do и done.
Команда break завершает выполнение только выполняемого в данный момент цикла, вызывая продолжение работы команд, стоящих после ближайшего done. Выход из n-уровневого вложенного цикла достигается командой break n.
Команда continue продолжает выполнение с ближайшего открытого оператора for, while или until, т.е. того, который содержит этот оператор continue. Вы также можете задать аргумент n в команде continue, и тогда выполнение будет продолжено с n-ного вложенного цикла: