Файл: Учебнометодическое пособие Томск 2016 2 удк 004. 451(075. 8) Ббк 32. 973. 2018. 2я73 к 754 Рецензенты.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 25.10.2023
Просмотров: 282
Скачиваний: 2
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
2.5.5 Управляющие операторы
Как и любой алгоритмический язык программирования, входной язык shellимеет управляющие операторы. Данные операторы предназначены для того, чтобы задавать порядок выполнения простых и составных команд. Рас- смотрим эти управляющие операторы.
1. Условный оператор if позволяет выполнить одну из нескольких вза- имоисключающих последовательностей команд shell. Данный оператор име- ет несколько форм записи, наиболее простая из которых следующая: ifкоманда-условие then последовательность команд fi
Работа данного оператора начинается с выполнения команды-условия.
Это может быть любая простая или составная команда, имеющая код заверше- ния. Но чаще всего в качестве этой команды используют команду test, вы- числяющую логическое выражение. Если при выполнении данной команды по- лучен нулевой код завершения (напомним, что такой код соответствует успешному завершению программы или значению «истина» логического выра- жения), то далее выполняется последовательность команд, записанная после ключевого слова then. При получении ненулевого кода завершения команды- условия выполнение условного оператора завершается без выполнения каких- либо действий.
Форма оператора if, предполагающая выполнение одной из двух после- довательностей команд: ifкоманда-условие then последовательность команд 1
else последовательность команд 2
fi
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Допустим, что переменная dir содержит простое имя каталога. Тогда следующая совокупность команд выполняет уничтожение каталога в том слу-
74 чае, если он пуст, в противном случае выполняется его переименование добав- лением к простому прежнему имени символа «a»:
$ ls $dir > fil1
$ if [ -s fil1 ]
> then
> mv $dir a$dir
> else
> rmdir $dir
> fi
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В данном примере содержимое заданного каталога помещается во вспо- могательный файл fil1. Если длина этого файла ненулевая, то каталог пере- именовывается, иначе – уничтожается.
Наиболее общая структура условного оператора: ifкоманда-условие 1
then последовательность команд 1
elifкоманда-условие 2
последовательность команд 2 elif else последовательность команд N
fi
Если был получен ненулевой код завершения команды-условия 1, то да- лее выполняется команда-условие 2. В случае успешного ее завершения выпол- няется последовательность команд 2. Выполнение команд-условий продолжа- ется до тех пор, пока очередная такая команда не даст нулевой код завершения.
В случае выполнения с ненулевым кодом завершения последней команды- условия выполняется последовательность команд, расположенная после ключе- вого слова else.
В отличие от распространенных языков программирования условный оператор if для shell обеспечивает не двух-, а многоальтернативный выбор.
Это приближает выразительные возможности данного управляющего оператора к возможностям оператора case.
75 2. Оператор варианта case позволяет выбрать для выполнения одну из нескольких последовательностей команд. Структура оператора: caseсловоin шаблон1) последовательность команд 1;; шаблон2) последовательность команд 2;;
....
*)последовательность команд N;; esac
Здесь слово – набор символов без пробелов или с пробелами. Наличие пробелов делает необходимым заключение слова в кавычки. При выполнении оператора caseслово последовательно сравнивается с шаблонами. Шаблон– слово, которое может иметь наряду с обычными символами метасимволы (?, *,
[ ]
). Если входное слово удовлетворяет первому шаблону, то выполняется первая последовательность команд, после чего делается выход из оператора case
. Иначе, входное слово сравнивается со вторым шаблоном и так далее. Ес- ли при этом обнаружится, что входное слово не отвечает ни одному из шабло- нов, то выполняется последовательность команд, которой предшествует шаб- лон «*». Обратим внимание, что любой шаблон отделяется от соответствующей последовательности команд символом «)», а каждая последо- вательность команд заканчивается двумя символами «;;».
В следующем примере в качестве входного слова используется имя файла – содержимое переменной name. В зависимости от суффикса имени файла этот файл обрабатывается или утилитой cat(вывод содержимого фай- ла), или интерпретатором shell(выполнение командного файла), или утили- той wc (вывод статистики о файле):
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ read name
$ case $name in
> *.txt) cat $name ;;
> *.sh) sh $name ;;
> *) wc $name ;;
> esac
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
76 3. Оператор цикла с перечислением for. Его структура: forпеременнаяinсписок слов do последовательность команд done
Заданная последовательность команд выполняется столько раз, сколько слов в списке. При этом указанная переменная последовательно принимает значения, равные словам из списка. Никакого дополнительного определения переменной, выполняемого перед ее использованием в операторе for, не тре- буется.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
В следующем примере все файлы с суффиксом txt, расположенные в поддереве данного пользователя, копируются в каталог k2:
$ for var in `find / -name ‘*.txt’`
> do
> cp $var /k2
>done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
4. Оператор цикла с условием while. Его структура: whileкоманда-условие do последовательность команд done
Аналогично оператору if, условие задается одной из команд shell. По- ка эта команда возвращает код возврата, равный 0, повторяется последователь- ность команд, заключенная между словами doиdone. При этом возможна си- туация, когда тело цикла не будет выполнено ни разу.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ whileread var1 var2
>do
> case $var1 in
>
1) echo $var2 >>file1 ;;
77
>
2) echo $var2 >>file2 ;;
>
*)echo $var2 >>file3 ;;
> esac
> done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Особенностью приведенного примера является использование вложенных управляющих структур: оператор выбора case вложен в оператор цикла while
. Выполнение цикла начинается с выполнения оператора read, который вводит строку с клавиатуры, записывая ее первое слово в качестве содержимого переменной var1, а все последующие слова – в качестве содержимого var2.
Допустим, что ввод строки символов завершился успешно и команда read вы- дала код возврата 0. В этом случае в зависимости от значения переменной var1 (1,2 или любое другое значение) содержимое введенной строки (за ис- ключением первого слова) записывается в один из трех файлов.
Выполнение данного цикла продолжается до тех пор, пока вместо набора очередной строки вы не наберете комбинацию клавиш <Ctrl>&<D>,что озна- чает для файла-клавиатуры «конец файла». В этом случае команда read воз- вратит ненулевой код возврата, и выполнение цикла завершится.
Переделаем записанную выше совокупность команд для обработки строк файла file. Простое перенаправление стандартного ввода для командыread в этом случае не помогает, так как на каждой итерации цикла будет произво- диться чтение одной и той же первой строки файла. Поэтому запишем конвей- ер, первая команда которого cat будет выполнять чтение строк файла:
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ cat file|
> whileread var1 var2
>do
> case$var1 in
>
1) echo $var2 >>file1 ;;
>
2) echo $var2 >>file2 ;;
>
*)echo $var2 >>file3 ;;
> esac
> done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
78 5. Оператор цикла с инверсным условием until. Его структура: untilкоманда-условие do последовательность команд done
Команды, заключенные между doиdone, повторяются до тех пор, пока команда-условие не выполнится с кодом завершения 0. Первое же выполнение условия означает выход из цикла. При этом возможна ситуация, когда тело цикла не будет выполнено ни разу. Нетрудно заметить, что операторы while и until будут выполнять одно и то же, если условие одного из них противо- положно условию другого.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Приведенная ниже последовательность команд выполняет то же самое, что и пример использования while, с тем отличием, что завершение ввода определяется не нажатием клавиш <Ctrl>&<D>, а вводом какого-то слова, например слова «!!»:
$ until [ `echo $var1` = ‘!!’ ]
> do
> read var1 var2
> case $var1 in
>
1) echo $var2 >>file1 ;;
>
2) echo $var2 >>file2 ;;
>
*)echo $var2 >>file3 ;;
> esac
> done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Обратите внимание, что в качестве условия записана команда test.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Запустив в первой половине дня следующую последовательность команд, мы получим на экране напоминание о начале времени обеда.
$ until date | fgrep 13:30:
> do
79
> sleep 60
> done && echo "Пора идти обедать" &
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В данном примере используется командный список, состоящий из опера- торов until и echo, соединенных символами «&&». Напомним, что такое со- единение обеспечивает запуск второй части командного списка только в случае успешного завершения его первой части. Запись в конце командного списка символа «&» обеспечивает запуск обеих его частей в фоновом режиме.
В качестве условия завершения цикла в операторе until записан кон- вейер команд date и fgrep. Первая из этих команд передает в свой стандарт- ный вывод текущую дату и время, а команда fgrep ищет в этих данных, полу- чаемых в своем стандартном вводе, заданное время (час и минуту). Для того чтобы во время ожидания не занимать бесполезно ЦП, в качестве оператора, повторяемого циклически, записан sleep. Этот оператор приостанавливает выполнение программы на указанное в нем число секунд (60), после чего опять проверяется условие завершения цикла. Так как программы, соответствующие перечисленным командам, выполняются в фоновом режиме, то вывод на экран результирующего сообщения «Пора идти обедать»может привести к не- которому искажению выходных данных программ, выполняемых в оператив- ном режиме.
6. Операторы завершения цикла break и продолжения цикла continue.
Общая структура оператора break: break число
Данный оператор завершает выполнение того цикла, в котором он запи- сан. Если в операторе задано число, то делается выход из соответствующего количества циклов, охватывающих оператор break. Отсутствие числа в опера- торе означает завершение одного цикла.
Общая структура оператора continue: continue число
Данный оператор вызывает переход к следующей итерации того цикла, в котором он стоит. Если в операторе задано число, то оно задает относитель- ный номер того цикла, который охватывает оператор continueи который должен продолжаться на своей следующей итерации. Отсутствие числа эквива- лентно 1.
80
Обычное интерактивное взаимодействие пользователя с shell, как пра- вило, не требует применения рассмотренных выше управляющих операторов.
В самом деле, зачем применять автоматический выбор последовательности вы- полняемых команд, если пользователь вынужден сам задавать с помощью кла- виатуры все возможные варианты выполнения таких команд. Для пользователя намного проще дождаться завершения предыдущей команды, а затем в зависи- мости от ее результатов выполнить набор следующей. Областью применения управляющих операторов являются командные файлы.
2.5.6 Командные файлы
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Командный файл – файл, содержащий список команд ин-
терпретатора команд ОС. Применение командных файлов позво-
ляет избежать повторения набора часто используемых команд,
и фактически каждый такой файл представляет собой виртуаль-
ную программу, записанную на входном языке ИК.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В операционной системе MS-DOS командный файл имеет обязательное расширение имени файла – bat. В UNIX командные файлы называются скрип-
тами, и к их имени не предъявляются столь жесткие требования. Заметим лишь, что имя скрипта часто начинается с символа «.», что позволяет не выво- дить на экран это имя при выполнении утилиты ls без записи специального ключа -a.
Так как по своей форме командный файл представляет собой обыкновен- ный текстовый файл, то для его получения и редактирования может быть ис- пользован любой текстовый редактор, например edit в MS-DOS или sedв
UNIX. Для записи скриптов можно использовать и утилиту cat.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Например, получим скриптfile, выполняющий задачу из пп. 2.5.5, ко- торая состоит в копировании всех файлов в поддереве данного пользователя, имеющих суффикс txt, в каталог k2:
$ cat >file
# Копирование всех файлов пользователя с суффиксом txt в
81
# каталог k2 for var in `find $HOME -name ‘*.txt’` do cp $var ${HOME}/k2
done
&
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Обратите внимание, что для задания корневого каталога поддерева поль- зователя используется не символ «», а переменная окружения HOME. Это поз- воляет существенно увеличить число способов запуска данного скрипта. Допу- стим, что командный файл fileнаходится в текущем каталоге, тогда он может быть запущен на выполнение следующими способами:
1) $ file,
2) $./file,
3) $ sh file,
4) $. file,
5) $../file.
В первых трех перечисленных способах запуска скриптаfile для его выполнения создается новый экземпляр интерпретатора shell. При этом в третьей команде этот новый shell задается явно, а в двух предыдущих коман- дах – неявно. При явном задании shell имя скрипта записывается в качестве параметра команды, следствием чего являются пониженные требования к пра- вам доступа пользователя к файлу-скрипту: достаточно иметь лишь право на чтение этого файла. Задание имени скрипта в качестве самой команды (приме- ры 1 и 2) требует наличия права пользователя на выполнение файла-скрипта.
(Вопрос о правах доступа к файлу будет рассмотрен нами в гл. 4.)
Отличием первой команды от второй является использование в ней про- стого имени файла-скрипта. В связи с этим напомним, что shell не произво- дит поиск исполняемого файла в текущем каталоге по умолчанию, и для этого требуется явное задание текущего каталога в переменной PATH с помощью ко- манды: PATH=${PATH}:./. В примере 2такого определения текущего ката- лога в переменной PATH не требуется.
В примерах 4 и 5 имя скрипта задается в качестве параметра команды «.» shell
. Наличие данной команды означает, что текущий shell должен вы- полнить заданный скрипт сам, а не порождать для этого новый экземпляр
82 shell
. Одним из следствий этого является то, что при выполнении скрипта могут использоваться любые переменные текущего shell, а не только пере- менные окружения. Что касается отличий между командами 4 и 5, то они ана- логичны различиям между командами 1 и 2.
Запуск скрипта из его родительского каталога имеет ограниченное при- менение и используется в основном при отладке скрипта. Больший интерес представляет запуск скрипта из любого текущего каталога. Для этого достаточ- но добавить абсолютное имя родительского каталога скрипта в переменную
PATH
, а затем использовать один из следующих способов:
1) $ file,
2) $. file.
Первая из этих команд запускает для выполнения скрипта новый экзем- пляр shell, а вторая – нет.
Скрипт может быть запущен на выполнение не только из командной строки, но и из другого командного файла аналогично обычной команде.
В этом случае запускаемый скрипт называется вложенным скриптом, а запус- кающий – главным скриптом.
Как и любая виртуальная программа, командный файл может иметь ком-
ментарии – любой текст, предваряемый особым символом. Для скриптов UNIX таким символом является «#». Комментарии различаются: а) вводные коммен-
тарии поясняют назначение и запуск командного файла; б) текущие коммен-
тарии используются для пояснения внутреннего содержимого командного файла. Напомним, что, как и для любого исходного текста программы, команд- ный файл без комментариев – черновик его автора.
Обычно shell, как и другие лингвистические процессоры, игнорирует комментарии. Исключением является комментарий, записанный в начале скрипта: если этот комментарий начинается с символа «!», то сразу за этим символом в комментарии записано абсолютное имя исполняемого файла, со- держащего тот shell, который должен быть запущен текущим shell для вы- полнения скрипта. (Напомним, что в UNIX-системах существуют различные варианты shell.) Примеры:
# ! /bin/sh запускается Bourne shell,
# ! /bin/csh запускается C shell,
# ! /bin/ksh запускается Korn shell.
83
Подобно обычным программам, командный файл может запускаться из командной строки shell (или из главного скрипта) с параметрами, которые, как обычно, отделяются друг от друга, а также от имени команды пробелами.
Благодаря параметрам пользователь влияет на выполнение командного файла, задавая для него исходную информацию. Так как порядок записи параметров для каждого командного файла фиксирован, то такие параметры называются
позиционными параметрами.
Например, скорректируем рассмотренный ранее пример скрипта так, что- бы скрипт имел два позиционных параметра: 1) требуемое окончание имени файла; 2) имя каталога, в который следует копировать найденные файлы. В ре- зультате вызов скрипта может выглядеть, например, следующим образом:
$ file.txt k2
Для того чтобы при выполнении командного файла shell мог использо- вать значения позиционных параметров, полученные от пользователя, каждый из этих параметров имеет свое имя, в качестве которого используется порядко- вый номер той позиции, которую занимает параметр в командной строке. При этом в качестве параметра 0 рассматривается имя скрипта. Например, в рассматриваемом примере позиционные параметры имеют следующие значе- ния: параметр 0 – file; параметр 1 – .txt; параметр 2 – k2.
Как и для переменной, значение позиционного параметра обозначается его именем, которому предшествует символ «$». При выполнении скрипта каждое значение его позиционного параметра заменяется его значением, полу- ченным из командной строки. Само это значение в командном файле изменено может быть только с помощью команды set, и поэтому позиционный параметр никогда не записывается в левой части операции присваивания и, как след- ствие, его имя всегда предваряется символом «$».
С учетом сделанных замечаний выполним запись рассматриваемого скрипта:
$ cat >file
# Копирование всех файлов с заданным окончанием име-
ни,
# принадлежащих данному пользователю, в заданный ка-
талог
# параметр 1 – окончание имени файла
# параметр 2 – имя каталога
for var in `find $HOME -name \*$1`
84 do cp $var ${HOME}/$2
done
<Ctrl>&<D>
Обратим внимание, что для «экранирования» символа «*» используется символ «\», а не кавычки. Это вызвано тем, что экранирующее действие сим- вола «\» распространяется только на соседний справа символ и поэтому не действует на символ «$», который в данном примере должен оставаться специ- альным символом shell, обозначая значение позиционного параметра.
Команда set, вводимая со своими параметрами, обеспечивает присваи- вание значений этих параметров позиционным параметрам скрипта.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Создадим скрипт k1, который сначала выводит на экран значения своих позиционных параметров, а затем изменяет эти значения с помощью команды set.
$ cat >k1
# Меняет значения своих параметров на a и b
# параметры 1 и 2 – любые слова
echo $1; echo $2 set a b echo $1; echo $2
<Ctrl>&<D>
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Допустим, что скрипт k1 запущен с параметрами 7 и 8:
$./k1 7 8 7
8 a b
Кроме позиционных параметров, передаваемых в shell при вызове скрипта, shell автоматически устанавливает значения следующих специаль-
ных параметров:
? – код завершения последней выполненной команды;
$ – системный номер процесса, выполняющего shell;
85
!– системный номер фонового процесса, запущенного последним;
#– число позиционных параметров, переданных в shell. Имя скрип- та (параметр 0) в это число не входит;
*– перечень позиционных параметров, переданных в shell. Этот перечень представляет собой строку, словами которой являются пози- ционные параметры.
Значения перечисленных специальных параметров могут использоваться не только в скриптах, но и в командных строках. При этом для записи значения параметра, как всегда, используется $.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Выполним запись скрипта, который добавляет к содержимому одного файла содержимое других файлов. Имя первого файла задается первым пара- метром скрипта, а имена других файлов – последующими параметрами.
$ cat >k2
# Добавление к содержимому файла содержимого других
файлов
# параметр 1 – имя исходного файла
# параметр 2, 3,… – имена добавляемых файлов
x=1 for i in $* do if [ $x –gt 1 ] then cat <$i >>$1 fi x=`expr $x + 1`
done
<Ctrl>&<D>
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В отличие от предыдущего скрипта число параметров при вызове данного скрипта может быть задано любое. Если это число меньше двух, то выполнение скрипта не приводит к изменению содержимого какого-либо файла. Заметим также, что оператор for i in $*во второй строке скрипта может быть за- менен на оператор for i. При этом используется следующее свойство опера-
86 тора for: при отсутствии части этого оператора, начинающейся со слова in, в качестве перечня значений заданной переменной (i) используется перечень по- зиционных параметров, заданный при вызове скрипта.
Особую роль играют инициализационные командные файлы. Они содер- жат команды ОС, выполняемые в самом начале сеанса работы пользователя.
В любой однопользовательской системе MS-DOS всего один такой файл – autoexec.bat
. В системе UNIX для любого пользователя первоначально вы- полняется инициализационный скрипт /etc/profile(или другой подобный файл). Кроме того, каждого пользователя обслуживает свой инициализацион- ный скрипт .profile, записанный самим пользователем в свой корневой ка- талог. Этот файл может содержать, например, приглашение к последующей ра- боте, задание путей поиска исполняемых файлов, «переделку» приглашений shell
. Первое из этих действий реализуется командой echo, а два послед- них – операциями присваивания, выполненными для переменных окружения.
После того, как мы рассмотрели работу ВС с точки зрения конкретного пользователя, перейдем к рассмотрению способов реализации такой работы в системе. При этом в качестве первого вопроса рассмотрим реализацию в си- стеме мультипрограммирования.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Контрольные вопросы по главе 2
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
1. Как при помощи команды cat создать файл?
2. Какие текстовые редакторы описаны в главе?
3. Какую служебную информацию о текстовом файле выводит команда wc?
4. Для чего используются метасимволы и приведите их?
5. Для чего в UNIX служит команда cp?
87
1 ... 4 5 6 7 8 9 10 11 ... 23
2.5.5 Управляющие операторы
Как и любой алгоритмический язык программирования, входной язык shellимеет управляющие операторы. Данные операторы предназначены для того, чтобы задавать порядок выполнения простых и составных команд. Рас- смотрим эти управляющие операторы.
1. Условный оператор if позволяет выполнить одну из нескольких вза- имоисключающих последовательностей команд shell. Данный оператор име- ет несколько форм записи, наиболее простая из которых следующая: ifкоманда-условие then последовательность команд fi
Работа данного оператора начинается с выполнения команды-условия.
Это может быть любая простая или составная команда, имеющая код заверше- ния. Но чаще всего в качестве этой команды используют команду test, вы- числяющую логическое выражение. Если при выполнении данной команды по- лучен нулевой код завершения (напомним, что такой код соответствует успешному завершению программы или значению «истина» логического выра- жения), то далее выполняется последовательность команд, записанная после ключевого слова then. При получении ненулевого кода завершения команды- условия выполнение условного оператора завершается без выполнения каких- либо действий.
Форма оператора if, предполагающая выполнение одной из двух после- довательностей команд: ifкоманда-условие then последовательность команд 1
else последовательность команд 2
fi
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Допустим, что переменная dir содержит простое имя каталога. Тогда следующая совокупность команд выполняет уничтожение каталога в том слу-
74 чае, если он пуст, в противном случае выполняется его переименование добав- лением к простому прежнему имени символа «a»:
$ ls $dir > fil1
$ if [ -s fil1 ]
> then
> mv $dir a$dir
> else
> rmdir $dir
> fi
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В данном примере содержимое заданного каталога помещается во вспо- могательный файл fil1. Если длина этого файла ненулевая, то каталог пере- именовывается, иначе – уничтожается.
Наиболее общая структура условного оператора: ifкоманда-условие 1
then последовательность команд 1
elifкоманда-условие 2
последовательность команд 2 elif else последовательность команд N
fi
Если был получен ненулевой код завершения команды-условия 1, то да- лее выполняется команда-условие 2. В случае успешного ее завершения выпол- няется последовательность команд 2. Выполнение команд-условий продолжа- ется до тех пор, пока очередная такая команда не даст нулевой код завершения.
В случае выполнения с ненулевым кодом завершения последней команды- условия выполняется последовательность команд, расположенная после ключе- вого слова else.
В отличие от распространенных языков программирования условный оператор if для shell обеспечивает не двух-, а многоальтернативный выбор.
Это приближает выразительные возможности данного управляющего оператора к возможностям оператора case.
75 2. Оператор варианта case позволяет выбрать для выполнения одну из нескольких последовательностей команд. Структура оператора: caseсловоin шаблон1) последовательность команд 1;; шаблон2) последовательность команд 2;;
....
*)последовательность команд N;; esac
Здесь слово – набор символов без пробелов или с пробелами. Наличие пробелов делает необходимым заключение слова в кавычки. При выполнении оператора caseслово последовательно сравнивается с шаблонами. Шаблон– слово, которое может иметь наряду с обычными символами метасимволы (?, *,
[ ]
). Если входное слово удовлетворяет первому шаблону, то выполняется первая последовательность команд, после чего делается выход из оператора case
. Иначе, входное слово сравнивается со вторым шаблоном и так далее. Ес- ли при этом обнаружится, что входное слово не отвечает ни одному из шабло- нов, то выполняется последовательность команд, которой предшествует шаб- лон «*». Обратим внимание, что любой шаблон отделяется от соответствующей последовательности команд символом «)», а каждая последо- вательность команд заканчивается двумя символами «;;».
В следующем примере в качестве входного слова используется имя файла – содержимое переменной name. В зависимости от суффикса имени файла этот файл обрабатывается или утилитой cat(вывод содержимого фай- ла), или интерпретатором shell(выполнение командного файла), или утили- той wc (вывод статистики о файле):
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ read name
$ case $name in
> *.txt) cat $name ;;
> *.sh) sh $name ;;
> *) wc $name ;;
> esac
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
76 3. Оператор цикла с перечислением for. Его структура: forпеременнаяinсписок слов do последовательность команд done
Заданная последовательность команд выполняется столько раз, сколько слов в списке. При этом указанная переменная последовательно принимает значения, равные словам из списка. Никакого дополнительного определения переменной, выполняемого перед ее использованием в операторе for, не тре- буется.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
В следующем примере все файлы с суффиксом txt, расположенные в поддереве данного пользователя, копируются в каталог k2:
$ for var in `find / -name ‘*.txt’`
> do
> cp $var /k2
>done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
4. Оператор цикла с условием while. Его структура: whileкоманда-условие do последовательность команд done
Аналогично оператору if, условие задается одной из команд shell. По- ка эта команда возвращает код возврата, равный 0, повторяется последователь- ность команд, заключенная между словами doиdone. При этом возможна си- туация, когда тело цикла не будет выполнено ни разу.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ whileread var1 var2
>do
> case $var1 in
>
1) echo $var2 >>file1 ;;
77
>
2) echo $var2 >>file2 ;;
>
*)echo $var2 >>file3 ;;
> esac
> done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Особенностью приведенного примера является использование вложенных управляющих структур: оператор выбора case вложен в оператор цикла while
. Выполнение цикла начинается с выполнения оператора read, который вводит строку с клавиатуры, записывая ее первое слово в качестве содержимого переменной var1, а все последующие слова – в качестве содержимого var2.
Допустим, что ввод строки символов завершился успешно и команда read вы- дала код возврата 0. В этом случае в зависимости от значения переменной var1 (1,2 или любое другое значение) содержимое введенной строки (за ис- ключением первого слова) записывается в один из трех файлов.
Выполнение данного цикла продолжается до тех пор, пока вместо набора очередной строки вы не наберете комбинацию клавиш <Ctrl>&<D>,что озна- чает для файла-клавиатуры «конец файла». В этом случае команда read воз- вратит ненулевой код возврата, и выполнение цикла завершится.
Переделаем записанную выше совокупность команд для обработки строк файла file. Простое перенаправление стандартного ввода для командыread в этом случае не помогает, так как на каждой итерации цикла будет произво- диться чтение одной и той же первой строки файла. Поэтому запишем конвей- ер, первая команда которого cat будет выполнять чтение строк файла:
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ cat file|
> whileread var1 var2
>do
> case$var1 in
>
1) echo $var2 >>file1 ;;
>
2) echo $var2 >>file2 ;;
>
*)echo $var2 >>file3 ;;
> esac
> done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
78 5. Оператор цикла с инверсным условием until. Его структура: untilкоманда-условие do последовательность команд done
Команды, заключенные между doиdone, повторяются до тех пор, пока команда-условие не выполнится с кодом завершения 0. Первое же выполнение условия означает выход из цикла. При этом возможна ситуация, когда тело цикла не будет выполнено ни разу. Нетрудно заметить, что операторы while и until будут выполнять одно и то же, если условие одного из них противо- положно условию другого.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Приведенная ниже последовательность команд выполняет то же самое, что и пример использования while, с тем отличием, что завершение ввода определяется не нажатием клавиш <Ctrl>&<D>, а вводом какого-то слова, например слова «!!»:
$ until [ `echo $var1` = ‘!!’ ]
> do
> read var1 var2
> case $var1 in
>
1) echo $var2 >>file1 ;;
>
2) echo $var2 >>file2 ;;
>
*)echo $var2 >>file3 ;;
> esac
> done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Обратите внимание, что в качестве условия записана команда test.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Запустив в первой половине дня следующую последовательность команд, мы получим на экране напоминание о начале времени обеда.
$ until date | fgrep 13:30:
> do
79
> sleep 60
> done && echo "Пора идти обедать" &
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В данном примере используется командный список, состоящий из опера- торов until и echo, соединенных символами «&&». Напомним, что такое со- единение обеспечивает запуск второй части командного списка только в случае успешного завершения его первой части. Запись в конце командного списка символа «&» обеспечивает запуск обеих его частей в фоновом режиме.
В качестве условия завершения цикла в операторе until записан кон- вейер команд date и fgrep. Первая из этих команд передает в свой стандарт- ный вывод текущую дату и время, а команда fgrep ищет в этих данных, полу- чаемых в своем стандартном вводе, заданное время (час и минуту). Для того чтобы во время ожидания не занимать бесполезно ЦП, в качестве оператора, повторяемого циклически, записан sleep. Этот оператор приостанавливает выполнение программы на указанное в нем число секунд (60), после чего опять проверяется условие завершения цикла. Так как программы, соответствующие перечисленным командам, выполняются в фоновом режиме, то вывод на экран результирующего сообщения «Пора идти обедать»может привести к не- которому искажению выходных данных программ, выполняемых в оператив- ном режиме.
6. Операторы завершения цикла break и продолжения цикла continue.
Общая структура оператора break: break число
Данный оператор завершает выполнение того цикла, в котором он запи- сан. Если в операторе задано число, то делается выход из соответствующего количества циклов, охватывающих оператор break. Отсутствие числа в опера- торе означает завершение одного цикла.
Общая структура оператора continue: continue число
Данный оператор вызывает переход к следующей итерации того цикла, в котором он стоит. Если в операторе задано число, то оно задает относитель- ный номер того цикла, который охватывает оператор continueи который должен продолжаться на своей следующей итерации. Отсутствие числа эквива- лентно 1.
80
Обычное интерактивное взаимодействие пользователя с shell, как пра- вило, не требует применения рассмотренных выше управляющих операторов.
В самом деле, зачем применять автоматический выбор последовательности вы- полняемых команд, если пользователь вынужден сам задавать с помощью кла- виатуры все возможные варианты выполнения таких команд. Для пользователя намного проще дождаться завершения предыдущей команды, а затем в зависи- мости от ее результатов выполнить набор следующей. Областью применения управляющих операторов являются командные файлы.
2.5.6 Командные файлы
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Командный файл – файл, содержащий список команд ин-
терпретатора команд ОС. Применение командных файлов позво-
ляет избежать повторения набора часто используемых команд,
и фактически каждый такой файл представляет собой виртуаль-
ную программу, записанную на входном языке ИК.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В операционной системе MS-DOS командный файл имеет обязательное расширение имени файла – bat. В UNIX командные файлы называются скрип-
тами, и к их имени не предъявляются столь жесткие требования. Заметим лишь, что имя скрипта часто начинается с символа «.», что позволяет не выво- дить на экран это имя при выполнении утилиты ls без записи специального ключа -a.
Так как по своей форме командный файл представляет собой обыкновен- ный текстовый файл, то для его получения и редактирования может быть ис- пользован любой текстовый редактор, например edit в MS-DOS или sedв
UNIX. Для записи скриптов можно использовать и утилиту cat.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Например, получим скриптfile, выполняющий задачу из пп. 2.5.5, ко- торая состоит в копировании всех файлов в поддереве данного пользователя, имеющих суффикс txt, в каталог k2:
$ cat >file
# Копирование всех файлов пользователя с суффиксом txt в
81
# каталог k2 for var in `find $HOME -name ‘*.txt’` do cp $var ${HOME}/k2
done
&
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Обратите внимание, что для задания корневого каталога поддерева поль- зователя используется не символ «», а переменная окружения HOME. Это поз- воляет существенно увеличить число способов запуска данного скрипта. Допу- стим, что командный файл fileнаходится в текущем каталоге, тогда он может быть запущен на выполнение следующими способами:
1) $ file,
2) $./file,
3) $ sh file,
4) $. file,
5) $../file.
В первых трех перечисленных способах запуска скриптаfile для его выполнения создается новый экземпляр интерпретатора shell. При этом в третьей команде этот новый shell задается явно, а в двух предыдущих коман- дах – неявно. При явном задании shell имя скрипта записывается в качестве параметра команды, следствием чего являются пониженные требования к пра- вам доступа пользователя к файлу-скрипту: достаточно иметь лишь право на чтение этого файла. Задание имени скрипта в качестве самой команды (приме- ры 1 и 2) требует наличия права пользователя на выполнение файла-скрипта.
(Вопрос о правах доступа к файлу будет рассмотрен нами в гл. 4.)
Отличием первой команды от второй является использование в ней про- стого имени файла-скрипта. В связи с этим напомним, что shell не произво- дит поиск исполняемого файла в текущем каталоге по умолчанию, и для этого требуется явное задание текущего каталога в переменной PATH с помощью ко- манды: PATH=${PATH}:./. В примере 2такого определения текущего ката- лога в переменной PATH не требуется.
В примерах 4 и 5 имя скрипта задается в качестве параметра команды «.» shell
. Наличие данной команды означает, что текущий shell должен вы- полнить заданный скрипт сам, а не порождать для этого новый экземпляр
82 shell
. Одним из следствий этого является то, что при выполнении скрипта могут использоваться любые переменные текущего shell, а не только пере- менные окружения. Что касается отличий между командами 4 и 5, то они ана- логичны различиям между командами 1 и 2.
Запуск скрипта из его родительского каталога имеет ограниченное при- менение и используется в основном при отладке скрипта. Больший интерес представляет запуск скрипта из любого текущего каталога. Для этого достаточ- но добавить абсолютное имя родительского каталога скрипта в переменную
PATH
, а затем использовать один из следующих способов:
1) $ file,
2) $. file.
Первая из этих команд запускает для выполнения скрипта новый экзем- пляр shell, а вторая – нет.
Скрипт может быть запущен на выполнение не только из командной строки, но и из другого командного файла аналогично обычной команде.
В этом случае запускаемый скрипт называется вложенным скриптом, а запус- кающий – главным скриптом.
Как и любая виртуальная программа, командный файл может иметь ком-
ментарии – любой текст, предваряемый особым символом. Для скриптов UNIX таким символом является «#». Комментарии различаются: а) вводные коммен-
тарии поясняют назначение и запуск командного файла; б) текущие коммен-
тарии используются для пояснения внутреннего содержимого командного файла. Напомним, что, как и для любого исходного текста программы, команд- ный файл без комментариев – черновик его автора.
Обычно shell, как и другие лингвистические процессоры, игнорирует комментарии. Исключением является комментарий, записанный в начале скрипта: если этот комментарий начинается с символа «!», то сразу за этим символом в комментарии записано абсолютное имя исполняемого файла, со- держащего тот shell, который должен быть запущен текущим shell для вы- полнения скрипта. (Напомним, что в UNIX-системах существуют различные варианты shell.) Примеры:
# ! /bin/sh запускается Bourne shell,
# ! /bin/csh запускается C shell,
# ! /bin/ksh запускается Korn shell.
83
Подобно обычным программам, командный файл может запускаться из командной строки shell (или из главного скрипта) с параметрами, которые, как обычно, отделяются друг от друга, а также от имени команды пробелами.
Благодаря параметрам пользователь влияет на выполнение командного файла, задавая для него исходную информацию. Так как порядок записи параметров для каждого командного файла фиксирован, то такие параметры называются
позиционными параметрами.
Например, скорректируем рассмотренный ранее пример скрипта так, что- бы скрипт имел два позиционных параметра: 1) требуемое окончание имени файла; 2) имя каталога, в который следует копировать найденные файлы. В ре- зультате вызов скрипта может выглядеть, например, следующим образом:
$ file.txt k2
Для того чтобы при выполнении командного файла shell мог использо- вать значения позиционных параметров, полученные от пользователя, каждый из этих параметров имеет свое имя, в качестве которого используется порядко- вый номер той позиции, которую занимает параметр в командной строке. При этом в качестве параметра 0 рассматривается имя скрипта. Например, в рассматриваемом примере позиционные параметры имеют следующие значе- ния: параметр 0 – file; параметр 1 – .txt; параметр 2 – k2.
Как и для переменной, значение позиционного параметра обозначается его именем, которому предшествует символ «$». При выполнении скрипта каждое значение его позиционного параметра заменяется его значением, полу- ченным из командной строки. Само это значение в командном файле изменено может быть только с помощью команды set, и поэтому позиционный параметр никогда не записывается в левой части операции присваивания и, как след- ствие, его имя всегда предваряется символом «$».
С учетом сделанных замечаний выполним запись рассматриваемого скрипта:
$ cat >file
# Копирование всех файлов с заданным окончанием име-
ни,
# принадлежащих данному пользователю, в заданный ка-
талог
# параметр 1 – окончание имени файла
# параметр 2 – имя каталога
for var in `find $HOME -name \*$1`
84 do cp $var ${HOME}/$2
done
<Ctrl>&<D>
Обратим внимание, что для «экранирования» символа «*» используется символ «\», а не кавычки. Это вызвано тем, что экранирующее действие сим- вола «\» распространяется только на соседний справа символ и поэтому не действует на символ «$», который в данном примере должен оставаться специ- альным символом shell, обозначая значение позиционного параметра.
Команда set, вводимая со своими параметрами, обеспечивает присваи- вание значений этих параметров позиционным параметрам скрипта.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Создадим скрипт k1, который сначала выводит на экран значения своих позиционных параметров, а затем изменяет эти значения с помощью команды set.
$ cat >k1
# Меняет значения своих параметров на a и b
# параметры 1 и 2 – любые слова
echo $1; echo $2 set a b echo $1; echo $2
<Ctrl>&<D>
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Допустим, что скрипт k1 запущен с параметрами 7 и 8:
$./k1 7 8 7
8 a b
Кроме позиционных параметров, передаваемых в shell при вызове скрипта, shell автоматически устанавливает значения следующих специаль-
ных параметров:
? – код завершения последней выполненной команды;
$ – системный номер процесса, выполняющего shell;
85
!– системный номер фонового процесса, запущенного последним;
#– число позиционных параметров, переданных в shell. Имя скрип- та (параметр 0) в это число не входит;
*– перечень позиционных параметров, переданных в shell. Этот перечень представляет собой строку, словами которой являются пози- ционные параметры.
Значения перечисленных специальных параметров могут использоваться не только в скриптах, но и в командных строках. При этом для записи значения параметра, как всегда, используется $.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Выполним запись скрипта, который добавляет к содержимому одного файла содержимое других файлов. Имя первого файла задается первым пара- метром скрипта, а имена других файлов – последующими параметрами.
$ cat >k2
# Добавление к содержимому файла содержимого других
файлов
# параметр 1 – имя исходного файла
# параметр 2, 3,… – имена добавляемых файлов
x=1 for i in $* do if [ $x –gt 1 ] then cat <$i >>$1 fi x=`expr $x + 1`
done
<Ctrl>&<D>
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В отличие от предыдущего скрипта число параметров при вызове данного скрипта может быть задано любое. Если это число меньше двух, то выполнение скрипта не приводит к изменению содержимого какого-либо файла. Заметим также, что оператор for i in $*во второй строке скрипта может быть за- менен на оператор for i. При этом используется следующее свойство опера-
86 тора for: при отсутствии части этого оператора, начинающейся со слова in, в качестве перечня значений заданной переменной (i) используется перечень по- зиционных параметров, заданный при вызове скрипта.
Особую роль играют инициализационные командные файлы. Они содер- жат команды ОС, выполняемые в самом начале сеанса работы пользователя.
В любой однопользовательской системе MS-DOS всего один такой файл – autoexec.bat
. В системе UNIX для любого пользователя первоначально вы- полняется инициализационный скрипт /etc/profile(или другой подобный файл). Кроме того, каждого пользователя обслуживает свой инициализацион- ный скрипт .profile, записанный самим пользователем в свой корневой ка- талог. Этот файл может содержать, например, приглашение к последующей ра- боте, задание путей поиска исполняемых файлов, «переделку» приглашений shell
. Первое из этих действий реализуется командой echo, а два послед- них – операциями присваивания, выполненными для переменных окружения.
После того, как мы рассмотрели работу ВС с точки зрения конкретного пользователя, перейдем к рассмотрению способов реализации такой работы в системе. При этом в качестве первого вопроса рассмотрим реализацию в си- стеме мультипрограммирования.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Контрольные вопросы по главе 2
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
1. Как при помощи команды cat создать файл?
2. Какие текстовые редакторы описаны в главе?
3. Какую служебную информацию о текстовом файле выводит команда wc?
4. Для чего используются метасимволы и приведите их?
5. Для чего в UNIX служит команда cp?
87
1 ... 4 5 6 7 8 9 10 11 ... 23
74 чае, если он пуст, в противном случае выполняется его переименование добав- лением к простому прежнему имени символа «a»:
$ ls $dir > fil1
$ if [ -s fil1 ]
> then
> mv $dir a$dir
> else
> rmdir $dir
> fi
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В данном примере содержимое заданного каталога помещается во вспо- могательный файл fil1. Если длина этого файла ненулевая, то каталог пере- именовывается, иначе – уничтожается.
Наиболее общая структура условного оператора: ifкоманда-условие 1
then последовательность команд 1
elifкоманда-условие 2
последовательность команд 2 elif else последовательность команд N
fi
Если был получен ненулевой код завершения команды-условия 1, то да- лее выполняется команда-условие 2. В случае успешного ее завершения выпол- няется последовательность команд 2. Выполнение команд-условий продолжа- ется до тех пор, пока очередная такая команда не даст нулевой код завершения.
В случае выполнения с ненулевым кодом завершения последней команды- условия выполняется последовательность команд, расположенная после ключе- вого слова else.
В отличие от распространенных языков программирования условный оператор if для shell обеспечивает не двух-, а многоальтернативный выбор.
Это приближает выразительные возможности данного управляющего оператора к возможностям оператора case.
75 2. Оператор варианта case позволяет выбрать для выполнения одну из нескольких последовательностей команд. Структура оператора: caseсловоin шаблон1) последовательность команд 1;; шаблон2) последовательность команд 2;;
....
*)последовательность команд N;; esac
Здесь слово – набор символов без пробелов или с пробелами. Наличие пробелов делает необходимым заключение слова в кавычки. При выполнении оператора caseслово последовательно сравнивается с шаблонами. Шаблон– слово, которое может иметь наряду с обычными символами метасимволы (?, *,
[ ]
). Если входное слово удовлетворяет первому шаблону, то выполняется первая последовательность команд, после чего делается выход из оператора case
. Иначе, входное слово сравнивается со вторым шаблоном и так далее. Ес- ли при этом обнаружится, что входное слово не отвечает ни одному из шабло- нов, то выполняется последовательность команд, которой предшествует шаб- лон «*». Обратим внимание, что любой шаблон отделяется от соответствующей последовательности команд символом «)», а каждая последо- вательность команд заканчивается двумя символами «;;».
В следующем примере в качестве входного слова используется имя файла – содержимое переменной name. В зависимости от суффикса имени файла этот файл обрабатывается или утилитой cat(вывод содержимого фай- ла), или интерпретатором shell(выполнение командного файла), или утили- той wc (вывод статистики о файле):
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ read name
$ case $name in
> *.txt) cat $name ;;
> *.sh) sh $name ;;
> *) wc $name ;;
> esac
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
76 3. Оператор цикла с перечислением for. Его структура: forпеременнаяinсписок слов do последовательность команд done
Заданная последовательность команд выполняется столько раз, сколько слов в списке. При этом указанная переменная последовательно принимает значения, равные словам из списка. Никакого дополнительного определения переменной, выполняемого перед ее использованием в операторе for, не тре- буется.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
В следующем примере все файлы с суффиксом txt, расположенные в поддереве данного пользователя, копируются в каталог k2:
$ for var in `find / -name ‘*.txt’`
> do
> cp $var /k2
>done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
4. Оператор цикла с условием while. Его структура: whileкоманда-условие do последовательность команд done
Аналогично оператору if, условие задается одной из команд shell. По- ка эта команда возвращает код возврата, равный 0, повторяется последователь- ность команд, заключенная между словами doиdone. При этом возможна си- туация, когда тело цикла не будет выполнено ни разу.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ whileread var1 var2
>do
> case $var1 in
>
1) echo $var2 >>file1 ;;
77
>
2) echo $var2 >>file2 ;;
>
*)echo $var2 >>file3 ;;
> esac
> done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Особенностью приведенного примера является использование вложенных управляющих структур: оператор выбора case вложен в оператор цикла while
. Выполнение цикла начинается с выполнения оператора read, который вводит строку с клавиатуры, записывая ее первое слово в качестве содержимого переменной var1, а все последующие слова – в качестве содержимого var2.
Допустим, что ввод строки символов завершился успешно и команда read вы- дала код возврата 0. В этом случае в зависимости от значения переменной var1 (1,2 или любое другое значение) содержимое введенной строки (за ис- ключением первого слова) записывается в один из трех файлов.
Выполнение данного цикла продолжается до тех пор, пока вместо набора очередной строки вы не наберете комбинацию клавиш <Ctrl>&<D>,что озна- чает для файла-клавиатуры «конец файла». В этом случае команда read воз- вратит ненулевой код возврата, и выполнение цикла завершится.
Переделаем записанную выше совокупность команд для обработки строк файла file. Простое перенаправление стандартного ввода для командыread в этом случае не помогает, так как на каждой итерации цикла будет произво- диться чтение одной и той же первой строки файла. Поэтому запишем конвей- ер, первая команда которого cat будет выполнять чтение строк файла:
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ cat file|
> whileread var1 var2
>do
> case$var1 in
>
1) echo $var2 >>file1 ;;
>
2) echo $var2 >>file2 ;;
>
*)echo $var2 >>file3 ;;
> esac
> done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
78 5. Оператор цикла с инверсным условием until. Его структура: untilкоманда-условие do последовательность команд done
Команды, заключенные между doиdone, повторяются до тех пор, пока команда-условие не выполнится с кодом завершения 0. Первое же выполнение условия означает выход из цикла. При этом возможна ситуация, когда тело цикла не будет выполнено ни разу. Нетрудно заметить, что операторы while и until будут выполнять одно и то же, если условие одного из них противо- положно условию другого.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Приведенная ниже последовательность команд выполняет то же самое, что и пример использования while, с тем отличием, что завершение ввода определяется не нажатием клавиш <Ctrl>&<D>, а вводом какого-то слова, например слова «!!»:
$ until [ `echo $var1` = ‘!!’ ]
> do
> read var1 var2
> case $var1 in
>
1) echo $var2 >>file1 ;;
>
2) echo $var2 >>file2 ;;
>
*)echo $var2 >>file3 ;;
> esac
> done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Обратите внимание, что в качестве условия записана команда test.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Запустив в первой половине дня следующую последовательность команд, мы получим на экране напоминание о начале времени обеда.
$ until date | fgrep 13:30:
> do
79
> sleep 60
> done && echo "Пора идти обедать" &
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В данном примере используется командный список, состоящий из опера- торов until и echo, соединенных символами «&&». Напомним, что такое со- единение обеспечивает запуск второй части командного списка только в случае успешного завершения его первой части. Запись в конце командного списка символа «&» обеспечивает запуск обеих его частей в фоновом режиме.
В качестве условия завершения цикла в операторе until записан кон- вейер команд date и fgrep. Первая из этих команд передает в свой стандарт- ный вывод текущую дату и время, а команда fgrep ищет в этих данных, полу- чаемых в своем стандартном вводе, заданное время (час и минуту). Для того чтобы во время ожидания не занимать бесполезно ЦП, в качестве оператора, повторяемого циклически, записан sleep. Этот оператор приостанавливает выполнение программы на указанное в нем число секунд (60), после чего опять проверяется условие завершения цикла. Так как программы, соответствующие перечисленным командам, выполняются в фоновом режиме, то вывод на экран результирующего сообщения «Пора идти обедать»может привести к не- которому искажению выходных данных программ, выполняемых в оператив- ном режиме.
6. Операторы завершения цикла break и продолжения цикла continue.
Общая структура оператора break: break число
Данный оператор завершает выполнение того цикла, в котором он запи- сан. Если в операторе задано число, то делается выход из соответствующего количества циклов, охватывающих оператор break. Отсутствие числа в опера- торе означает завершение одного цикла.
Общая структура оператора continue: continue число
Данный оператор вызывает переход к следующей итерации того цикла, в котором он стоит. Если в операторе задано число, то оно задает относитель- ный номер того цикла, который охватывает оператор continueи который должен продолжаться на своей следующей итерации. Отсутствие числа эквива- лентно 1.
80
Обычное интерактивное взаимодействие пользователя с shell, как пра- вило, не требует применения рассмотренных выше управляющих операторов.
В самом деле, зачем применять автоматический выбор последовательности вы- полняемых команд, если пользователь вынужден сам задавать с помощью кла- виатуры все возможные варианты выполнения таких команд. Для пользователя намного проще дождаться завершения предыдущей команды, а затем в зависи- мости от ее результатов выполнить набор следующей. Областью применения управляющих операторов являются командные файлы.
2.5.6 Командные файлы
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Командный файл – файл, содержащий список команд ин-
терпретатора команд ОС. Применение командных файлов позво-
ляет избежать повторения набора часто используемых команд,
и фактически каждый такой файл представляет собой виртуаль-
ную программу, записанную на входном языке ИК.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В операционной системе MS-DOS командный файл имеет обязательное расширение имени файла – bat. В UNIX командные файлы называются скрип-
тами, и к их имени не предъявляются столь жесткие требования. Заметим лишь, что имя скрипта часто начинается с символа «.», что позволяет не выво- дить на экран это имя при выполнении утилиты ls без записи специального ключа -a.
Так как по своей форме командный файл представляет собой обыкновен- ный текстовый файл, то для его получения и редактирования может быть ис- пользован любой текстовый редактор, например edit в MS-DOS или sedв
UNIX. Для записи скриптов можно использовать и утилиту cat.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Например, получим скриптfile, выполняющий задачу из пп. 2.5.5, ко- торая состоит в копировании всех файлов в поддереве данного пользователя, имеющих суффикс txt, в каталог k2:
$ cat >file
# Копирование всех файлов пользователя с суффиксом txt в
81
# каталог k2 for var in `find $HOME -name ‘*.txt’` do cp $var ${HOME}/k2
done
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Обратите внимание, что для задания корневого каталога поддерева поль- зователя используется не символ «», а переменная окружения HOME. Это поз- воляет существенно увеличить число способов запуска данного скрипта. Допу- стим, что командный файл fileнаходится в текущем каталоге, тогда он может быть запущен на выполнение следующими способами:
1) $ file,
2) $./file,
3) $ sh file,
4) $. file,
5) $../file.
В первых трех перечисленных способах запуска скриптаfile для его выполнения создается новый экземпляр интерпретатора shell. При этом в третьей команде этот новый shell задается явно, а в двух предыдущих коман- дах – неявно. При явном задании shell имя скрипта записывается в качестве параметра команды, следствием чего являются пониженные требования к пра- вам доступа пользователя к файлу-скрипту: достаточно иметь лишь право на чтение этого файла. Задание имени скрипта в качестве самой команды (приме- ры 1 и 2) требует наличия права пользователя на выполнение файла-скрипта.
(Вопрос о правах доступа к файлу будет рассмотрен нами в гл. 4.)
Отличием первой команды от второй является использование в ней про- стого имени файла-скрипта. В связи с этим напомним, что shell не произво- дит поиск исполняемого файла в текущем каталоге по умолчанию, и для этого требуется явное задание текущего каталога в переменной PATH с помощью ко- манды: PATH=${PATH}:./. В примере 2такого определения текущего ката- лога в переменной PATH не требуется.
В примерах 4 и 5 имя скрипта задается в качестве параметра команды «.» shell
. Наличие данной команды означает, что текущий shell должен вы- полнить заданный скрипт сам, а не порождать для этого новый экземпляр
82 shell
. Одним из следствий этого является то, что при выполнении скрипта могут использоваться любые переменные текущего shell, а не только пере- менные окружения. Что касается отличий между командами 4 и 5, то они ана- логичны различиям между командами 1 и 2.
Запуск скрипта из его родительского каталога имеет ограниченное при- менение и используется в основном при отладке скрипта. Больший интерес представляет запуск скрипта из любого текущего каталога. Для этого достаточ- но добавить абсолютное имя родительского каталога скрипта в переменную
PATH
, а затем использовать один из следующих способов:
1) $ file,
2) $. file.
Первая из этих команд запускает для выполнения скрипта новый экзем- пляр shell, а вторая – нет.
Скрипт может быть запущен на выполнение не только из командной строки, но и из другого командного файла аналогично обычной команде.
В этом случае запускаемый скрипт называется вложенным скриптом, а запус- кающий – главным скриптом.
Как и любая виртуальная программа, командный файл может иметь ком-
ментарии – любой текст, предваряемый особым символом. Для скриптов UNIX таким символом является «#». Комментарии различаются: а) вводные коммен-
тарии поясняют назначение и запуск командного файла; б) текущие коммен-
тарии используются для пояснения внутреннего содержимого командного файла. Напомним, что, как и для любого исходного текста программы, команд- ный файл без комментариев – черновик его автора.
Обычно shell, как и другие лингвистические процессоры, игнорирует комментарии. Исключением является комментарий, записанный в начале скрипта: если этот комментарий начинается с символа «!», то сразу за этим символом в комментарии записано абсолютное имя исполняемого файла, со- держащего тот shell, который должен быть запущен текущим shell для вы- полнения скрипта. (Напомним, что в UNIX-системах существуют различные варианты shell.) Примеры:
# ! /bin/sh запускается Bourne shell,
# ! /bin/csh запускается C shell,
# ! /bin/ksh запускается Korn shell.
83
Подобно обычным программам, командный файл может запускаться из командной строки shell (или из главного скрипта) с параметрами, которые, как обычно, отделяются друг от друга, а также от имени команды пробелами.
Благодаря параметрам пользователь влияет на выполнение командного файла, задавая для него исходную информацию. Так как порядок записи параметров для каждого командного файла фиксирован, то такие параметры называются
позиционными параметрами.
Например, скорректируем рассмотренный ранее пример скрипта так, что- бы скрипт имел два позиционных параметра: 1) требуемое окончание имени файла; 2) имя каталога, в который следует копировать найденные файлы. В ре- зультате вызов скрипта может выглядеть, например, следующим образом:
$ file.txt k2
Для того чтобы при выполнении командного файла shell мог использо- вать значения позиционных параметров, полученные от пользователя, каждый из этих параметров имеет свое имя, в качестве которого используется порядко- вый номер той позиции, которую занимает параметр в командной строке. При этом в качестве параметра 0 рассматривается имя скрипта. Например, в рассматриваемом примере позиционные параметры имеют следующие значе- ния: параметр 0 – file; параметр 1 – .txt; параметр 2 – k2.
Как и для переменной, значение позиционного параметра обозначается его именем, которому предшествует символ «$». При выполнении скрипта каждое значение его позиционного параметра заменяется его значением, полу- ченным из командной строки. Само это значение в командном файле изменено может быть только с помощью команды set, и поэтому позиционный параметр никогда не записывается в левой части операции присваивания и, как след- ствие, его имя всегда предваряется символом «$».
С учетом сделанных замечаний выполним запись рассматриваемого скрипта:
$ cat >file
# Копирование всех файлов с заданным окончанием име-
ни,
# принадлежащих данному пользователю, в заданный ка-
талог
# параметр 1 – окончание имени файла
# параметр 2 – имя каталога
for var in `find $HOME -name \*$1`
84 do cp $var ${HOME}/$2
done
<Ctrl>&<D>
Обратим внимание, что для «экранирования» символа «*» используется символ «\», а не кавычки. Это вызвано тем, что экранирующее действие сим- вола «\» распространяется только на соседний справа символ и поэтому не действует на символ «$», который в данном примере должен оставаться специ- альным символом shell, обозначая значение позиционного параметра.
Команда set, вводимая со своими параметрами, обеспечивает присваи- вание значений этих параметров позиционным параметрам скрипта.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Создадим скрипт k1, который сначала выводит на экран значения своих позиционных параметров, а затем изменяет эти значения с помощью команды set.
$ cat >k1
# Меняет значения своих параметров на a и b
# параметры 1 и 2 – любые слова
echo $1; echo $2 set a b echo $1; echo $2
<Ctrl>&<D>
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Допустим, что скрипт k1 запущен с параметрами 7 и 8:
$./k1 7 8 7
8 a b
Кроме позиционных параметров, передаваемых в shell при вызове скрипта, shell автоматически устанавливает значения следующих специаль-
ных параметров:
? – код завершения последней выполненной команды;
$ – системный номер процесса, выполняющего shell;
85
!– системный номер фонового процесса, запущенного последним;
#– число позиционных параметров, переданных в shell. Имя скрип- та (параметр 0) в это число не входит;
*– перечень позиционных параметров, переданных в shell. Этот перечень представляет собой строку, словами которой являются пози- ционные параметры.
Значения перечисленных специальных параметров могут использоваться не только в скриптах, но и в командных строках. При этом для записи значения параметра, как всегда, используется $.
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
Выполним запись скрипта, который добавляет к содержимому одного файла содержимое других файлов. Имя первого файла задается первым пара- метром скрипта, а имена других файлов – последующими параметрами.
$ cat >k2
# Добавление к содержимому файла содержимого других
файлов
# параметр 1 – имя исходного файла
# параметр 2, 3,… – имена добавляемых файлов
x=1 for i in $* do if [ $x –gt 1 ] then cat <$i >>$1 fi x=`expr $x + 1`
done
<Ctrl>&<D>
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В отличие от предыдущего скрипта число параметров при вызове данного скрипта может быть задано любое. Если это число меньше двух, то выполнение скрипта не приводит к изменению содержимого какого-либо файла. Заметим также, что оператор for i in $*во второй строке скрипта может быть за- менен на оператор for i. При этом используется следующее свойство опера-
86 тора for: при отсутствии части этого оператора, начинающейся со слова in, в качестве перечня значений заданной переменной (i) используется перечень по- зиционных параметров, заданный при вызове скрипта.
Особую роль играют инициализационные командные файлы. Они содер- жат команды ОС, выполняемые в самом начале сеанса работы пользователя.
В любой однопользовательской системе MS-DOS всего один такой файл – autoexec.bat
. В системе UNIX для любого пользователя первоначально вы- полняется инициализационный скрипт /etc/profile(или другой подобный файл). Кроме того, каждого пользователя обслуживает свой инициализацион- ный скрипт .profile, записанный самим пользователем в свой корневой ка- талог. Этот файл может содержать, например, приглашение к последующей ра- боте, задание путей поиска исполняемых файлов, «переделку» приглашений shell
. Первое из этих действий реализуется командой echo, а два послед- них – операциями присваивания, выполненными для переменных окружения.
После того, как мы рассмотрели работу ВС с точки зрения конкретного пользователя, перейдем к рассмотрению способов реализации такой работы в системе. При этом в качестве первого вопроса рассмотрим реализацию в си- стеме мультипрограммирования.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Контрольные вопросы по главе 2
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
1. Как при помощи команды cat создать файл?
2. Какие текстовые редакторы описаны в главе?
3. Какую служебную информацию о текстовом файле выводит команда wc?
4. Для чего используются метасимволы и приведите их?
5. Для чего в UNIX служит команда cp?
87
1 ... 4 5 6 7 8 9 10 11 ... 23
3 Системная поддержка мультипрограммирования
3.1 Общие сведения
Любая мультипрограммная система, независимо от того, является ли она однопользовательской или многопользовательской, обеспечивает одновремен- ное выполнение нескольких последовательных обрабатывающих программ, прикладных и (или) системных. Термин последовательная программа означает, что даже при наличии в системе нескольких ЦП в любой момент времени не может выполняться более одной команды этой программы.
В недалеком прошлом все обрабатывающие программы относились к классу последовательных программ. В настоящее время значительная часть обрабатывающих программ относится к классу параллельных программ. Для
параллельной программы характерно то, что несколько ее команд могут выпол- няться одновременно (параллельно). Наличие нескольких ЦП делает при этом возможным физическую параллельность. Если же в системе всего один ЦП, то применительно к параллельной программе имеет место логическая (виртуаль- ная) параллельность. Как правило, параллельную программу можно предста- вить в виде совокупности нескольких последовательных программ, каждая из которых выполняется в значительной степени асинхронно (независимо). Не- трудно предположить, что одновременное выполнение даже одной параллель- ной программы возможно только в мультипрограммной системе.
Однопрограммная ОС, например MS-DOS, также позволяет нескольким выполняющимся последовательным программам одновременно находиться в ОП. Наличие таких программ обусловлено тем, что одна обрабатывающая программа может выполнить запуск другой программы. После выполнения та- кого запуска родительская программа переходит в состояние бездействия до тех пор, пока дочерняя программа не завершится и не возвратит управление в ту точку родительской программы, из которой она была запущена. Следова- тельно, программы, находящиеся одновременно в ОП, связаны друг с другом по управлению аналогично процедурам. При этом какая-либо асинхронность
(параллельность) между программами отсутствует, а реализация в системе управляющих взаимодействий между программами не вызывает каких-либо трудностей.
Следует заметить, что полностью избавиться от асинхронного выполне- ния программ в однопрограммных системах не удается. Это объясняется прин-
88 ципиальной асинхронностью событий, происходящих на ПУ, по отношению к программе, выполняемой в данный момент времени на ЦП. Заметим, что в данном случае речь идет об асинхронности между обрабатывающей програм- мой, с одной стороны, и управляющими подпрограммами (обработчиками ап- паратных прерываний) – с другой. При этом асинхронность обеспечивается, в основном, не программно (то есть операционной системой), а аппаратно.
В данной главе рассматриваются постановки задач, решение которых обеспечивает наличие мультипрограммирования в системе, а также изучаются методы решения этих задач. Реализация данных методов в системе UNIX будет рассмотрена в гл. 5 и 6.
3.2 Процессы
Важнейшим понятием любой мультипрограммной системы является по- нятие процесса. В данном разделе мы будем использовать наиболее простое определение:
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Процесс – одно выполнение последовательной программы.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Так как параллельную программу можно представить в виде совокупно- сти нескольких последовательных программ, то выполнение каждой из этих последовательных программ есть отдельный процесс. Характерной особенно- стью процесса является то, что он никак не связан по управлению с огромным большинством других процессов. Следствием этого является параллельность
процессов: этап выполнения одного процесса никак не связан с этапом выпол- нения другого процесса.
Так как процесс есть выполнение программы, то кто-то должен начать
(инициировать) это выполнение. Это делает другой процесс, являющийся по отношению к первому процессу «процессом-отцом». Общим предком всех
(или почти всех) процессов в системе является процесс, созданный сразу же по- сле выполнения начальной загрузки ОС в оперативную память. Допустим, что этот процесс есть выполнение программы с именем init. Тогда «дочерни- ми» процессами процесса init являются системные процессы, выполняющие служебные функции по поддержанию работоспособности системы, а также ин- терпретатор команд ОС, например shell.
89
После того как ИК (shell) будет создан и инициирован процессом init
, он перейдет к ожиданию команды пользователя, набираемой на клавиа- туре или вводимой с помощью мыши в качестве выбранного варианта из меню, предлагаемого пользователю. В любом случае ИК получает имя программы, подлежащей выполнению путем создания и инициирования соответствующего программного процесса. Принципиальной особенностью мультипрограммной системы является то, что запуск новой «дочерней» программы может быть вы- полнен до завершения предыдущей «дочерней» программы. Поэтому в отличие от однопрограммной системы количество одновременно существующих дочер- них процессов может быть более одного. Например, одновременно запускаются программы, образующие конвейер (см. пп. 2.5.3). Параллельно с программой в оперативном режиме могут выполняться программы в фоновом режиме.
Например, пусть пользователь ввел следующую команду:
$ find / -name ‘f*’| tee file1 | fgrep f1 >file2 & script7
, где script7
– командный файл следующего содержания:
$ cat script7 cat file3 echo ++++ cat file4
Тогда в начале обработки данной команды shell дерево процессов при- нимает вид, приведенный на рисунке 3.1. Обратим внимание, что выполнение команды echoне приводит к появлению нового процесса, так как эту команду выполняет не отдельная утилита, а подпрограмма самого shell. Кроме того, заметим, что не могут существовать одновременно два процесса cat, так как каждый из них должен выполняться в оперативном режиме (требуется экран), и поэтому один из процессов изображен пунктиром.
Заметим, что символьное имя программы (имя исполняемого файла) ис- пользуется нами в качестве имени процесса только с целью наглядности. В дей- ствительности оно не может использоваться в качестве имени процесса, так как применительно к процессу не обладает свойством уникальности. Подобным свойством обладает номер процесса, используемый в качестве системного, про- граммного, а также пользовательского имени процесса.
Находясь в командной строке shell, пользователь может получить ин- формацию о своих программных процессах, используя команду ps. Ее приме-
90 нение без флагов позволяет вывести на экран минимум информации о процес- сах.
Рис. 3.1 Пример дерева процессов
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ ps
PID TTY TIME CMD
145 ttyp4 0:01 /user/bin/sh
313 ttyp4 0:03 /user/bin/ed
431 ttyp4 0:01 /user/bin/ps
$
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В выдаче команды:
1) PID – номер процесса;
2) TTY– имя управляющего терминала процесса (co – операторская консоль; ? – процесс не управляется терминалом). Терминальное управление процессами рассматривается в пп. 3.4.2;
3) TIME – затраты времени ЦП на выполнение процесса;
4) CMD – имя команды shell, выполнение которой привело к созданию процесса.
Некоторые флаги этой команды:
-e – вывод информации обо всех без исключения процессах;
-f – вывод достаточно подробной информации о процессах: систем- ное имя пользователя, номер процесса-отца, время создания процесса;
91
-l – вывод наиболее подробной информации о процессах. Содержа- ние этой информации будет рассмотрено нами в последующих разде- лах.
В рассматриваемом примере – два процесса shell и два процесса cat.
Использование несколькими процессами одинаковых программ приводит к мысли о возможности использования ими одного и того же экземпляра про- граммы. Такая идея реализуема в том случае, если программа процесса являет- ся реентерабельной. Программа называется реентерабельной, если содержимое занимаемой ею области памяти не изменяется при выполнении программы.
Так как выполнение любой сколько-нибудь полезной программы требует выполнения операций записи в ОП, то необходимо отделить все изменяемые данные в отдельную область. Неизменную область памяти программы будем называть сегментом кода, а изменяемую – сегментом данных. При этом сег- мент кода может содержать не только команды (код) программы, но и ее неиз- меняемые данные (константы). При совместном использовании несколькими процессами одной и той же программы каждый из них использует единствен- ный общий экземпляр сегмента кода, но использует свой сегмент данных. Так как сегмент кода неизменен, то выполнение одного процесса никак не влияет на выполнение других процессов.
В мультипрограммных системах широко используются не только реенте- рабельные программы, но и реентерабельные подпрограммы (процедуры).
Обычные нереентерабельные подпрограммы «встраиваются» в загрузочный модуль (исполняемый файл) программы при его получении редактором связей
(см. п. 2.4). Так как подобное связывание программы производится до начала ее выполнения, то оно называется статическим связыванием. При этом предпола- гается, что если несколько программ вызывают одну и ту же подпрограмму
(процедуру), то каждая из них будет обладать своим отдельным экземпляром этой процедуры. Следствием такого «тиражирования» являются повышенные затраты памяти. Использование реентерабельных подпрограмм позволяет эти затраты существенно сократить.
Реентерабельные подпрограммы собраны в динамически компонуемые
библиотеки – DLL (dynamic link library). Связывание этих подпрограмм с про- граммой осуществляется динамическим редактором связей во время загрузки программы в ОП. Загрузочный модуль программы, выполняемой в среде UNIX, содержит не только перечень требуемых DLL, но и имя файла, содержащего ди- намический редактор связей. Получив управление при загрузке программы, этот
92 редактор связей обеспечивает загрузку в память системы недостающих DLL, а за- тем помещает численные адреса требуемых подпрограмм в команды программы, выполняющие вызов подпрограмм. Закончив свою работу, динамический редак- тор связей передает управление в точку входа загруженной программы. Парал- лельные процессы, использующие DLL, работают с одним и тем же экземпляром сегмента кода этой библиотеки, но используют ее различные сегменты данных.
После того как процесс создан, он может вступать в управляющие и ин- формационные взаимодействия с другими процессами. Примерами управляю- щих взаимодействий являются операции создания и уничтожения процессов.
Примером информационного взаимодействия является обмен информацией между процессами, образующими конвейер.
Для реализации управляющих и информационных взаимодействий между процессами им требуется помощь со стороны ОС.
3.3 Ресурсы
В отличие от однопрограммной ОС, выполняющей распределение ресур- сов системы между программами, являющимися «близкими родственниками», мультипрограммная ОС должна заниматься их распределением между парал- лельными процессами, в общем случае «чужими» по отношению друг к другу.
Следствием этого является то, что основные решения по распределению ресур- сов между процессами теперь должен принимать не прикладной программист, а сама ОС. Поэтому наряду с программными процессами ресурсы являются важнейшими объектами, подлежащими управлению со стороны мультипро- граммной ОС [4].
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Логическим ресурсом, или просто ресурсом, называется
объект, нехватка которого приводит к блокированию процесса и
переводу его в состояние «Сон».
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Подробная речь о состояниях процесса будет идти в п. 5.1, а пока лишь заметим, что в данном состоянии процесс не может выполняться на ЦП до тех пор, пока причина блокирования не будет устранена.
На рисунке 3.2 приведена классификация ресурсов. К аппаратным ресур-
сам относятся: ЦП, ОП, устройства ввода-вывода, устройства ВП, носители ВП.
Все аппаратные ресурсы являются повторно используемыми. То есть после то-
93 го, как данный ресурс стал не нужен тому процессу, которому он был выделен, он может быть распределен какому-то другому процессу.
Рис. 3.2 Классификация ресурсов
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Под информационными ресурсами понимаются какие-то
данные, не получив доступ к которым конкретный программный
процесс блокируется.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Фактически информационные ресурсы представляют собой области па- мяти, заполненные какой-то полезной информацией. В отличие от них пустые области ОП и ВП являются аппаратными ресурсами.
Информационные ресурсы делятся на повторно используемые и потреб- ляемые.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Потребляемым ресурсом является сообщение, которое один
процесс выдает другому процессу.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
После того как сообщение обработано процессом-потребителем, оно больше не нужно и может быть уничтожено.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Повторно используемыми информационными ресурсами яв-
ляются данные, совместно используемые несколькими процессами.
94
К таким ресурсам относятся файлы (в том числе библиотеки), ба-
зы данных, совместно используемые программы, а также некото-
рые структуры данных в ОП. Повторно используемые ресурсы (как
аппаратные, так и информационные) делятся на параллельно и по-
следовательно используемые.
Последовательно используемый ресурс выделяется некото-
рому процессу и не может быть перераспределен до тех пор, пока
первому процессу этот ресурс не будет больше нужен. К таким
ресурсам относятся многие устройства ввода-вывода и ВП (тер-
минал, сканер, стример и т. д.), а также последовательно исполь-
зуемые программы – программы, которые не являются реентера-
бельными, но которые должны обслуживать запросы нескольких
параллельных процессов. Примером последовательно используемой
программы является ядро UNIX (рассматривается в п. 4.3).
Параллельно используемые ресурсы могут действительно
использоваться одновременно несколькими процессами (физиче-
ская параллельность), или они используются параллельно лишь
виртуально (виртуальная параллельность). Примеры первого ти-
па: ОП, ВП прямого доступа (например, магнитный диск), реенте-
рабельные программы и DLL (при наличии в ВС нескольких ЦП).
Примеры второго типа: ЦП, доступ к параллельно используемому
устройству (например, к дисководу), реентерабельные программы
и DLL (при одном ЦП).
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Покажем разницу между физически параллельными и виртуально парал- лельными ресурсами на примере использования двух ресурсов – пространства памяти на магнитном диске и доступа к дисководу, на котором этот диск уста- новлен. В то время как свободное пространство диска реально делится на обла- сти между процессами, выполняющими операции записи в файлы, доступ к дисководу в каждый конкретный момент времени имеет лишь один приклад- ной процесс. В следующий момент доступ к устройству ВП может быть пере- дан другому процессу, затем опять возвращен первому процессу и т. д.
Наличие в системе разнообразных ресурсов, а также наличие параллель- ных процессов, которым эти ресурсы требуются, приводит к необходимости решения ОС следующих задач:
95 1) распределение повторно используемых ресурсов между процессами, учитывающее: а) свойства распределяемого ресурса; б) потребности тех процессов, которым ресурс распределяется. Ре- шение данной задачи рассматривается в гл. 5, 6 на примере наибо- лее важных ресурсов ВС – оперативной памяти и времени ЦП;
2) синхронизация параллельных процессов, совместно использующих информационные ресурсы, потребляемые или повторно используе- мые. Методы решения этой задачи рассматриваются в пп. 3.4.3, 3.4.4 и п. 3.5;
3) оказание помощи процессам, при совместном использовании ими по- вторно используемых ресурсов, по устранению такого неприятного явления, как тупики;
4) защита информации, принадлежащей какому-то процессу от воздей- ствия других процессов. При этом наиболее важная задача, решаемая с целью поддержки мультипрограммирования, – защита информации в ОП. Эта задача решается не столько программными, сколько аппа- ратными средствами. Ее решение рассматривается в пп. 6.2.3.
3.4 Синхронизация параллельных процессов
Параллельные процессы, существующие в ВС, нуждаются в синхрониза- ции.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Синхронизация – согласование этапов выполнения двух или
более параллельных процессов путем обмена ими инициирующими
(командными) воздействиями.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Перечислим некоторые задачи, решаемые с помощью синхронизации процессов:
1) обработка программой процесса некоторых аппаратных прерываний;
2) терминальное управление процессами;
3) синхронизация параллельных процессов, выполняющих действия с общей областью ОП;
4) синхронизация параллельных процессов, выполняющих информаци- онный обмен, используя общую область ОП.
96
Для решения первых двух задач в UNIX-системах используются сигналы, а для решения двух последних задач – семафоры.
1 ... 5 6 7 8 9 10 11 12 ... 23
88 ципиальной асинхронностью событий, происходящих на ПУ, по отношению к программе, выполняемой в данный момент времени на ЦП. Заметим, что в данном случае речь идет об асинхронности между обрабатывающей програм- мой, с одной стороны, и управляющими подпрограммами (обработчиками ап- паратных прерываний) – с другой. При этом асинхронность обеспечивается, в основном, не программно (то есть операционной системой), а аппаратно.
В данной главе рассматриваются постановки задач, решение которых обеспечивает наличие мультипрограммирования в системе, а также изучаются методы решения этих задач. Реализация данных методов в системе UNIX будет рассмотрена в гл. 5 и 6.
3.2 Процессы
Важнейшим понятием любой мультипрограммной системы является по- нятие процесса. В данном разделе мы будем использовать наиболее простое определение:
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Процесс – одно выполнение последовательной программы.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Так как параллельную программу можно представить в виде совокупно- сти нескольких последовательных программ, то выполнение каждой из этих последовательных программ есть отдельный процесс. Характерной особенно- стью процесса является то, что он никак не связан по управлению с огромным большинством других процессов. Следствием этого является параллельность
процессов: этап выполнения одного процесса никак не связан с этапом выпол- нения другого процесса.
Так как процесс есть выполнение программы, то кто-то должен начать
(инициировать) это выполнение. Это делает другой процесс, являющийся по отношению к первому процессу «процессом-отцом». Общим предком всех
(или почти всех) процессов в системе является процесс, созданный сразу же по- сле выполнения начальной загрузки ОС в оперативную память. Допустим, что этот процесс есть выполнение программы с именем init. Тогда «дочерни- ми» процессами процесса init являются системные процессы, выполняющие служебные функции по поддержанию работоспособности системы, а также ин- терпретатор команд ОС, например shell.
89
После того как ИК (shell) будет создан и инициирован процессом init
, он перейдет к ожиданию команды пользователя, набираемой на клавиа- туре или вводимой с помощью мыши в качестве выбранного варианта из меню, предлагаемого пользователю. В любом случае ИК получает имя программы, подлежащей выполнению путем создания и инициирования соответствующего программного процесса. Принципиальной особенностью мультипрограммной системы является то, что запуск новой «дочерней» программы может быть вы- полнен до завершения предыдущей «дочерней» программы. Поэтому в отличие от однопрограммной системы количество одновременно существующих дочер- них процессов может быть более одного. Например, одновременно запускаются программы, образующие конвейер (см. пп. 2.5.3). Параллельно с программой в оперативном режиме могут выполняться программы в фоновом режиме.
Например, пусть пользователь ввел следующую команду:
$ find / -name ‘f*’| tee file1 | fgrep f1 >file2 & script7
, где script7
– командный файл следующего содержания:
$ cat script7 cat file3 echo ++++ cat file4
Тогда в начале обработки данной команды shell дерево процессов при- нимает вид, приведенный на рисунке 3.1. Обратим внимание, что выполнение команды echoне приводит к появлению нового процесса, так как эту команду выполняет не отдельная утилита, а подпрограмма самого shell. Кроме того, заметим, что не могут существовать одновременно два процесса cat, так как каждый из них должен выполняться в оперативном режиме (требуется экран), и поэтому один из процессов изображен пунктиром.
Заметим, что символьное имя программы (имя исполняемого файла) ис- пользуется нами в качестве имени процесса только с целью наглядности. В дей- ствительности оно не может использоваться в качестве имени процесса, так как применительно к процессу не обладает свойством уникальности. Подобным свойством обладает номер процесса, используемый в качестве системного, про- граммного, а также пользовательского имени процесса.
Находясь в командной строке shell, пользователь может получить ин- формацию о своих программных процессах, используя команду ps. Ее приме-
90 нение без флагов позволяет вывести на экран минимум информации о процес- сах.
Рис. 3.1 Пример дерева процессов
· · · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · ·
$ ps
PID TTY TIME CMD
145 ttyp4 0:01 /user/bin/sh
313 ttyp4 0:03 /user/bin/ed
431 ttyp4 0:01 /user/bin/ps
$
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В выдаче команды:
1) PID – номер процесса;
2) TTY– имя управляющего терминала процесса (co – операторская консоль; ? – процесс не управляется терминалом). Терминальное управление процессами рассматривается в пп. 3.4.2;
3) TIME – затраты времени ЦП на выполнение процесса;
4) CMD – имя команды shell, выполнение которой привело к созданию процесса.
Некоторые флаги этой команды:
-e – вывод информации обо всех без исключения процессах;
-f – вывод достаточно подробной информации о процессах: систем- ное имя пользователя, номер процесса-отца, время создания процесса;
91
-l – вывод наиболее подробной информации о процессах. Содержа- ние этой информации будет рассмотрено нами в последующих разде- лах.
В рассматриваемом примере – два процесса shell и два процесса cat.
Использование несколькими процессами одинаковых программ приводит к мысли о возможности использования ими одного и того же экземпляра про- граммы. Такая идея реализуема в том случае, если программа процесса являет- ся реентерабельной. Программа называется реентерабельной, если содержимое занимаемой ею области памяти не изменяется при выполнении программы.
Так как выполнение любой сколько-нибудь полезной программы требует выполнения операций записи в ОП, то необходимо отделить все изменяемые данные в отдельную область. Неизменную область памяти программы будем называть сегментом кода, а изменяемую – сегментом данных. При этом сег- мент кода может содержать не только команды (код) программы, но и ее неиз- меняемые данные (константы). При совместном использовании несколькими процессами одной и той же программы каждый из них использует единствен- ный общий экземпляр сегмента кода, но использует свой сегмент данных. Так как сегмент кода неизменен, то выполнение одного процесса никак не влияет на выполнение других процессов.
В мультипрограммных системах широко используются не только реенте- рабельные программы, но и реентерабельные подпрограммы (процедуры).
Обычные нереентерабельные подпрограммы «встраиваются» в загрузочный модуль (исполняемый файл) программы при его получении редактором связей
(см. п. 2.4). Так как подобное связывание программы производится до начала ее выполнения, то оно называется статическим связыванием. При этом предпола- гается, что если несколько программ вызывают одну и ту же подпрограмму
(процедуру), то каждая из них будет обладать своим отдельным экземпляром этой процедуры. Следствием такого «тиражирования» являются повышенные затраты памяти. Использование реентерабельных подпрограмм позволяет эти затраты существенно сократить.
Реентерабельные подпрограммы собраны в динамически компонуемые
библиотеки – DLL (dynamic link library). Связывание этих подпрограмм с про- граммой осуществляется динамическим редактором связей во время загрузки программы в ОП. Загрузочный модуль программы, выполняемой в среде UNIX, содержит не только перечень требуемых DLL, но и имя файла, содержащего ди- намический редактор связей. Получив управление при загрузке программы, этот
92 редактор связей обеспечивает загрузку в память системы недостающих DLL, а за- тем помещает численные адреса требуемых подпрограмм в команды программы, выполняющие вызов подпрограмм. Закончив свою работу, динамический редак- тор связей передает управление в точку входа загруженной программы. Парал- лельные процессы, использующие DLL, работают с одним и тем же экземпляром сегмента кода этой библиотеки, но используют ее различные сегменты данных.
После того как процесс создан, он может вступать в управляющие и ин- формационные взаимодействия с другими процессами. Примерами управляю- щих взаимодействий являются операции создания и уничтожения процессов.
Примером информационного взаимодействия является обмен информацией между процессами, образующими конвейер.
Для реализации управляющих и информационных взаимодействий между процессами им требуется помощь со стороны ОС.
3.3 Ресурсы
В отличие от однопрограммной ОС, выполняющей распределение ресур- сов системы между программами, являющимися «близкими родственниками», мультипрограммная ОС должна заниматься их распределением между парал- лельными процессами, в общем случае «чужими» по отношению друг к другу.
Следствием этого является то, что основные решения по распределению ресур- сов между процессами теперь должен принимать не прикладной программист, а сама ОС. Поэтому наряду с программными процессами ресурсы являются важнейшими объектами, подлежащими управлению со стороны мультипро- граммной ОС [4].
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Логическим ресурсом, или просто ресурсом, называется
объект, нехватка которого приводит к блокированию процесса и
переводу его в состояние «Сон».
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Подробная речь о состояниях процесса будет идти в п. 5.1, а пока лишь заметим, что в данном состоянии процесс не может выполняться на ЦП до тех пор, пока причина блокирования не будет устранена.
На рисунке 3.2 приведена классификация ресурсов. К аппаратным ресур-
сам относятся: ЦП, ОП, устройства ввода-вывода, устройства ВП, носители ВП.
Все аппаратные ресурсы являются повторно используемыми. То есть после то-
93 го, как данный ресурс стал не нужен тому процессу, которому он был выделен, он может быть распределен какому-то другому процессу.
Рис. 3.2 Классификация ресурсов
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Под информационными ресурсами понимаются какие-то
данные, не получив доступ к которым конкретный программный
процесс блокируется.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Фактически информационные ресурсы представляют собой области па- мяти, заполненные какой-то полезной информацией. В отличие от них пустые области ОП и ВП являются аппаратными ресурсами.
Информационные ресурсы делятся на повторно используемые и потреб- ляемые.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Потребляемым ресурсом является сообщение, которое один
процесс выдает другому процессу.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
После того как сообщение обработано процессом-потребителем, оно больше не нужно и может быть уничтожено.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Повторно используемыми информационными ресурсами яв-
ляются данные, совместно используемые несколькими процессами.
94
К таким ресурсам относятся файлы (в том числе библиотеки), ба-
зы данных, совместно используемые программы, а также некото-
рые структуры данных в ОП. Повторно используемые ресурсы (как
аппаратные, так и информационные) делятся на параллельно и по-
следовательно используемые.
Последовательно используемый ресурс выделяется некото-
рому процессу и не может быть перераспределен до тех пор, пока
первому процессу этот ресурс не будет больше нужен. К таким
ресурсам относятся многие устройства ввода-вывода и ВП (тер-
минал, сканер, стример и т. д.), а также последовательно исполь-
зуемые программы – программы, которые не являются реентера-
бельными, но которые должны обслуживать запросы нескольких
параллельных процессов. Примером последовательно используемой
программы является ядро UNIX (рассматривается в п. 4.3).
Параллельно используемые ресурсы могут действительно
использоваться одновременно несколькими процессами (физиче-
ская параллельность), или они используются параллельно лишь
виртуально (виртуальная параллельность). Примеры первого ти-
па: ОП, ВП прямого доступа (например, магнитный диск), реенте-
рабельные программы и DLL (при наличии в ВС нескольких ЦП).
Примеры второго типа: ЦП, доступ к параллельно используемому
устройству (например, к дисководу), реентерабельные программы
и DLL (при одном ЦП).
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Покажем разницу между физически параллельными и виртуально парал- лельными ресурсами на примере использования двух ресурсов – пространства памяти на магнитном диске и доступа к дисководу, на котором этот диск уста- новлен. В то время как свободное пространство диска реально делится на обла- сти между процессами, выполняющими операции записи в файлы, доступ к дисководу в каждый конкретный момент времени имеет лишь один приклад- ной процесс. В следующий момент доступ к устройству ВП может быть пере- дан другому процессу, затем опять возвращен первому процессу и т. д.
Наличие в системе разнообразных ресурсов, а также наличие параллель- ных процессов, которым эти ресурсы требуются, приводит к необходимости решения ОС следующих задач:
95 1) распределение повторно используемых ресурсов между процессами, учитывающее: а) свойства распределяемого ресурса; б) потребности тех процессов, которым ресурс распределяется. Ре- шение данной задачи рассматривается в гл. 5, 6 на примере наибо- лее важных ресурсов ВС – оперативной памяти и времени ЦП;
2) синхронизация параллельных процессов, совместно использующих информационные ресурсы, потребляемые или повторно используе- мые. Методы решения этой задачи рассматриваются в пп. 3.4.3, 3.4.4 и п. 3.5;
3) оказание помощи процессам, при совместном использовании ими по- вторно используемых ресурсов, по устранению такого неприятного явления, как тупики;
4) защита информации, принадлежащей какому-то процессу от воздей- ствия других процессов. При этом наиболее важная задача, решаемая с целью поддержки мультипрограммирования, – защита информации в ОП. Эта задача решается не столько программными, сколько аппа- ратными средствами. Ее решение рассматривается в пп. 6.2.3.
3.4 Синхронизация параллельных процессов
Параллельные процессы, существующие в ВС, нуждаются в синхрониза- ции.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Синхронизация – согласование этапов выполнения двух или
более параллельных процессов путем обмена ими инициирующими
(командными) воздействиями.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Перечислим некоторые задачи, решаемые с помощью синхронизации процессов:
1) обработка программой процесса некоторых аппаратных прерываний;
2) терминальное управление процессами;
3) синхронизация параллельных процессов, выполняющих действия с общей областью ОП;
4) синхронизация параллельных процессов, выполняющих информаци- онный обмен, используя общую область ОП.
96
Для решения первых двух задач в UNIX-системах используются сигналы, а для решения двух последних задач – семафоры.
1 ... 5 6 7 8 9 10 11 12 ... 23
3.4.1 Синхронизация с помощью сигналов
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Сигнал – команда, которую один процесс посылает другому
процессу (процессам) с целью оказания влияния на ход выполнения
этого процесса (процессов).
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В отличие от других известных нам команд, к которым относятся машин- ные команды и команды shell, команды-сигналы не имеют операндов (пара- метров) и представляют собой только коды операций. Другой особенностью сигнала является то, что моменты выдачи и обработки сигнала могут быть до- вольно существенно разнесены во времени. Причиной этого является то, что в момент выдачи сигнала процесс-отправитель, а в момент обработки сигнала процесс-получатель обязательно должны выполняться на ЦП. Еще одной осо- бенностью сигналов является их ненакапливаемость. То есть, если в момент по- ступления сигнала в процесс еще не начата обработка предыдущего однотипно- го сигнала, вновь пришедший сигнал теряется.
Вспомним, что в однопрограммной системе (например, в MS-DOS) воз- никающие в системе прерывания обрабатываются или подпрограммами ядра или подпрограммами прикладной программы. При этом прикладная программа может перехватывать и обрабатывать любые прерывания. Подобный подход совершенно неприемлем для мультипрограммной системы, в которой обработ- ка прерываний должна находиться под управлением ОС. С другой стороны, полное отстранение процессов от обработки прерываний делает их выполнение негибким, лишая их многих возможностей. Следствием этого является предо- ставление процессам возможности участвовать в обработке некоторых типов прерываний. При этом процесс может обрабатывать не сам аппаратный сигнал прерывания, а его преобразованную форму – сигнал, выдаваемый обработчи- ком прерываний.
К прерываниям, которые не преобразуются в сигналы, а обрабатываются полностью обработчиками ядра ОС, относятся программные прерывания и большинство внешних аппаратных прерываний. Преобразуются в сигналы лишь прерывания-исключения, а также некоторые внешние аппаратные преры- вания. С другой стороны, источниками сигналов могут быть не только обработ-
97 чики перечисленных прерываний, но и сами процессы, использующие для этого специально предназначенные системные вызовы.
Современная UNIX-система различает примерно 30 различных типов сигналов, каждый из которых имеет свое системное имя – номер сигнала, а также программное (символьное) имя. Перечислим символьные имена некото- рых из сигналов, источниками которых являются обработчики прерываний:
1) SIGFPE – сигнал возникновения переполнения результата, например из-за деления на 0, во время выполнения текущей машинной команды процесса. Обработка по умолчанию – завершение процесса и создание файла core в текущем каталоге. Этот файл может использоваться при запуске утилиты-отладчика с целью обнаружения ошибки в програм- ме процесса;
2) SIGILL – сигнал выполнения программой процесса недопустимой машинной команды. Обработка по умолчанию – завершение процесса и создание файла core в текущем каталоге;
3) SIGEGV – попытка программы процесса обратиться к ячейке ОП, ко- торая или не существует, или для доступа к которой у процесса нет прав. Обработка по умолчанию – завершение процесса и создание файла core в текущем каталоге;
4) SIGTRAP– сигнал о возникновении исключения «трассировка». Та- кой сигнал используется отладчиками программ;
5) SIGPWR– сигнал угрозы потери питания;
6) SIGALRM– сигнал таймера. Передается обработчиком прерываний таймера при завершении интервала времени, заданного ранее этому обработчику с помощью специально предназначенного для этого си- стемного вызова.
Сигналы, выдаваемые процессами:
1) SIGKILL – сигнал уничтожения процесса. Единственно возможная реакция процесса на этот сигнал – немедленное завершение;
2) SIGSTOP – сигнал останова процесса. Единственно возможная реак- ция процесса на этот сигнал – переход в состояние «Останов»;
3) SIGCONT – продолжение работы остановленного процесса. Если про- цесс не был ранее остановлен, то он игнорирует данный сигнал;
4) SIGTERM – сигнал «добровольного» завершения процесса. Получив данный сигнал, процесс может подготовиться к своему уничтожению,
98 выполнив самые неотложные действия. Часто выдача данного сигнала предшествует выдаче сигналаSIGKILL;
5) SIGCHLD – сигнал, посылаемый процессу-отцу при останове или при завершении дочернего процесса. Источник сигнала – дочерний про- цесс;
6) SIGUSR1, SIGUSR2 – пользовательские сигналы. Они предназначены для взаимодействия между прикладными процессами, характер кото- рого определяется разработчиком прикладных программ.
Для того чтобы послать сигнал другому процессу (процессам), программа данного процесса должна обратиться за помощью к ОС. Для получения любой помощи со стороны системы обрабатывающая программа должна содержать специальную команду – системный вызов.
При записи системных вызовов нами будет использоваться следующее правило. Во-первых, с целью пояснения смысла вызова его имя будет записы- ваться прописными русскими буквами курсивом. Во-вторых, параметры вызова перечисляются через запятую в круглых скобках после имени вызова.
В-третьих, входные параметры вызова отделяются от его выходных параметров символами «||». Причем входные параметры располагаются слева, а выход- ные – справа от этих символов. В-четвертых, справа от системного вызова в круглых скобках помещается аналогичный системный вызов UNIX, записанный на языке Си.
Системный вызов для посылки сигнала:
ПОСЛАТЬ_СИГНАЛ (i p
, S ||), (на Си – kill), где i p
– номер процесса, которому посылается сигнал;
S – имя сигнала.
Если i p
= 0, то сигнал посылается всем процессам из той же группы про- цессов, что и отправитель сигнала. При i p
= –1 сигнал посылается всем про- цессам данного пользователя. Понятие группы процессов рассматривается ни- же.
3.4.2 Терминальное управление процессами
Любая интерактивная ВС имеет среди своих ПУ по крайней мере один терминал.
99
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Терминал – совокупность устройства ввода и устройства
вывода.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Терминал позволяет пользователю выполнять запуск программ. Кроме того, пользователь системы имеет возможность влиять на выполнение любого своего программного процесса путем нажатия специальных комбинаций кла- виш на клавиатуре. Поэтому терминал пользователя является для всех его про- граммных процессов управляющим терминалом.
Вспомним, что корнем поддерева процессов, принадлежащих конкретно- му пользователю, является процесс shell (интерпретатор команд ОС). Этот процесс осуществляет «открытие» управляющего терминала, делая его доступ- ным не только для себя, но и для своих будущих «потомков». Такое множество потомков процессаshell называется сеансом, а процесс shell – лидером се-
анса. Каждый сеанс в системе имеет уникальное системное имя – номер сеанса, совпадающий с номером процесса, являющегося лидером сеанса.
Управляющее воздействие передается процессу от своего управляющего терминала в виде сигнала. Примером является сигнал освобождения линии
SIGHUP
, выдаваемый одновременно всем процессам сеанса при завершении работы пользователя и отключении им терминала. Стандартная реакция про- цесса на этот сигнал – завершение.
Отношение процессов сеанса к управляющему терминалу неодинаково.
Среди них есть процессы-изгои, выполняемые в фоновом режиме. (Напомним, что в фоновом режиме программа процесса не выполняет операций ввода- вывода с терминалом. Для запуска из командной строки процесса или конвейе- ра процессов в фоновом режиме необходимо в конце командной строки набрать символ «&».)
При этом процессы, запущенные из одной командной строки, обычно ин- формационно связаны друг с другом. Так как пользователю удобно выполнять с терминала совместное управление этими процессами, то процесс-shell объ- являет свои совместно запускаемые дочерние программные процессы единой
группой процессов. Каждая группа процессов имеет уникальный для всей си- стемы номер группы процессов, в качестве которогоshell назначает номер одного из процессов – членов группы. Такой процесс называется лидером груп-
100
пы процессов. Для создания новой группы или для включения процесса в уже существующую группуshell обращается к ядру, используя системный вызов:
УСТАНОВИТЬ_ГРУППУ_ПРОЦЕССОВ (i g
, i p
||), (на Си – setpgid), где i g
– номер группы процессов; i
p
– номер процесса.
Еслиi g
= i p
, то в результате данного системного вызова создается новая группа, лидером которой является процессi p
. Иначе, процессi p
включается в уже существующую группу с номеромi g
Вообще говоря, сразу же после своего создания процесс уже принадлежит к той же группе, что и процесс-отец. Смену группы у дочерних процессов shell производит с целью «отмежеваться» от них при получении ими различ- ных сигналов. В любом случае каждый процесс сеанса в конкретный момент времени принадлежит одной (и только одной) группе процессов [5].
Среди всех групп процессов, на которые разбито множество процессов одного сеанса, одна группа имеет особое значение.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Это оперативная группа – совокупность процессов, выпол-
няемых в оперативном режиме, в котором процесс может выпол-
нять информационный обмен с управляющим терминалом.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Например,shell выполняет диалог с пользователем только в оператив- ном режиме. Введя команду или группу команд без завершающего символа
«&», shell запускает соответствующую группу процессов в оперативном ре- жиме, не забыв при этом установить себе другую группу процессов (фоновую).
В результатеshell становится недосягаем для сигналов, воздействующих од- новременно на все члены оперативной группы. Перечислим эти сигналы:
1) SIGINT – сигнал прерывания программы. Выдается одновременно всем процессам оперативной группы вследствие нажатия пользовате- лем клавиши
2) SIGQUIT – сигнал о выходе. Выдается одновременно всем процессам оперативной группы вследствие нажатия пользователем клавиш
101 3) SIGTSTP – терминальный сигнал останова. Выдается одновременно всем процессам оперативной группы вследствие нажатия пользовате- лем клавиш
Следующие два сигнала выдаются подпрограммами управления термина- лом в том случае, если фоновый процесс сделает попытку выполнить операцию ввода-вывода с управляющим терминалом:
1) SIGTTIN– сигнал о попытке ввода с терминала фоновым процессом.
Обработка по умолчанию – перевод процесса в состояние «Останов»;
2) SIGTTOU– сигнал о попытке вывода на терминал фоновым процес- сом. Обработка по умолчанию – перевод процесса в состояние «Оста- нов».
Существуют системные вызовы, позволяющие процессу делать оператив- ной любую фоновую группу своего сеанса, и наоборот – делать фоновой опера- тивную группу. Несмотря на то что любой процесс может воспользоваться эти- ми вызовами, на практике это делает только shell. Кроме того, любой процесс, не являющийся лидером сеанса, может покинуть свой прежний сеанс и стать лидером нового сеанса, воспользовавшись системным вызовом:
УСТАНОВИТЬ_СЕАНС (||), (на Си – setsid).
Данный вызов не имеет параметров, так как номер нового сеанса будет совпадать с номером процесса, сделавшего вызов. В случае успешного завер- шения вызова появится новый сеанс и новая группа, единственным членом и лидером которых будет процесс, сделавший вызов. Отличительной чертой нового сеанса является то, что он не имеет управляющего терминала.
Новый сеанс может или вообще не иметь управляющего терминала, или же его лидер должен открыть новый управляющий терминал. Так как реальный терминал уже занят прежним сеансом, то в качестве нового терминала обычно открывается псевдотерминал. Подробно псевдотерминалы рассматриваются в п. 4.1, а пока лишь заметим, что они используются для доступа к системе уда- ленных пользователей.
Лидер нового сеанса вообще не открывает управляющий терминал в том случае, если он хочет оградить себя и своих потомков от воздействия сигналов с управляющего терминала. Именно с этой целью в данном случае и создается новый сеанс. Подобный процесс, не связанный ни с каким управляющим тер- миналом, называется демоном. Демоны широко используются ядром ОС для