Файл: Учебнометодическое пособие Томск 2016 2 удк 004. 451(075. 8) Ббк 32. 973. 2018. 2я73 к 754 Рецензенты.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 07.11.2023

Просмотров: 349

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

СОДЕРЖАНИЕ

2.3 Утилиты Как отмечалось ранее, основной функцией утилиты является перенос ин- формации в пределах ВС. При рассмотрении каждой конкретной утилиты поль- зователя системы интересуют функции этой утилиты, а также ее имя, использу- емое для передачи в систему через пользовательский интерфейс в качестве команды для ОС. При работе с системой UNIX общий формат такой пользова- тельской команды выглядит так: имя [флаги] [файлы], где 1) квадратные скобки заключают необязательную часть команды; 2) имя – пользовательское имя исполняемого файла, содержащего загру- зочный модуль (машинный код) утилиты; 3) файлы – имена файлов, над которыми утилита выполняет свои дей- ствия. Различают входные файлы, информация из которых (или инфор- мация о которых) используется утилитой в качестве ее исходных дан- ных, а также выходные файлы, в которые утилита помещает результаты своей работы. По умолчанию большинство системных утилит исполь- зуют в качестве входного файла клавиатуру, а в качестве выходного файла – экран. Эти устройства (и соответствующие им файлы) часто называют соответственно стандартным вводом и стандартным выво-дом; 4) флаги – двоичные параметры команды, уточняющие действие, кото- рое должна выполнить запускаемая утилита. Флаг задается своим име- нем из одной буквы, которой предшествует символ «–». Некоторые флаги уточняются своими параметрами, которые отделяются от имени флага пробелами. 42 Ниже приводится краткое описание утилит, используемых пользователя- ми операционной системы UNIX для работы с файлами. После имени каждой утилиты в скобках приводится название аналогичной или близкой команды в MS-DOS. Рассматриваемые утилиты можно разбить на группы: 1) идентифика- ция и установка текущего каталога; 2) создание каталогов и анализ их содер- жимого; 3) копирование, переименование и перенос файлов; 4) уничтожение файлов и каталогов; 5) работа с текстовой информацией; 6) поиск информации; 7) выдача справочной информации; 8) упрощение пользовательского интерфей- са. Рассмотрение утилит, участвующих в обеспечении многопользовательской работы ВС, будет выполнено в других разделах. 1. Идентификация и установка текущего каталог:а) вывод абсолютного имени текущего каталога (в MS-DOSотсутствует, так как это имя является частью приглашения к вводу команды): pwd.Это наиболее простая команда UNIX, которая не имеет ни одного пара- метра; б) смена текущего каталога (в MS-DOS – cd): cd [каталог].Если каталог опущен, то текущим каталогом станет корневой каталог поддерева каталогов данного пользователя (например, каталогvladна рисун- ке 2.7). Имя каталога может быть как абсолютным, так и относительным. Задание абсолютного имени позволяет сделать текущим любой каталог, а задание отно- сительного имени – только каталог-потомок действующего текущего каталога. Если в начале относительного имени каталога записать символы «/», то сме- щение нового текущего каталога вычисляется относительно корневого каталога данного пользователя. Если в качестве имени каталога задать символы «..», то новым текущим каталогом станет «родитель» действующего текущего катало- га. Данная утилита не имеет флагов. К этому добавим, что cd, вообще гово- ря, не является утилитой в полном смысле этого слова, так как она существует не в виде отдельного исполняемого файла, а в виде подпрограммы ОС (точнее – ее интерпретатора команд). Подобное свойство обусловлено небольшими раз- мерами данной подпрограммы и для пользователя ВС не заметно. 43 2. Создание каталогов и анализ их содержимого:а) создание нового каталога (каталогов) (в MS-DOS – mkdir): mkdir каталоги.Имена создаваемых каталогов могут быть заданы в любом виде: простые, относительные, абсолютные. Единственный флаг данной утилиты: -m – создать каталог с заданным режимом доступа. Режимы доступа бу- дут рассмотрены в п. 4.2; б) вывод содержимого каталога на экран (в MS-DOS – dir): ls [каталог или файлы].Если параметр опущен, то на экран выводится содержимое текущего ка- талога, иначе – содержимое заданного каталога. Если заданы имена файлов, то на экран выводятся сведения об этих файлах, если их имена присутствуют в те- кущем каталоге. Данная утилита имеет 23 флага. Приведем только некоторые из них: 1) -R – рекурсивный вывод подкаталогов заданного каталога; 2) -F – пометить исполняемые файлы символом «*», каталоги – симво- лом «/», а символические связи – «@»; 3) -l – вывод наиболее подробной информации о файлах; 4) -a – вывод списка всех файлов и подкаталогов заданного каталога (по умолчанию имена, начинающиеся с символа «.» не выводятся). 3. Копирование, переименование и перенос файлов: а) копирование файла (в MS-DOS – copy): cp исходный_файл (или каталог) конечный_файл (или каталог).Первый параметр команды задает источник копирования, а второй пара- метр – место размещения копии. При этом копирование может производиться из файла в файл, из файла в каталог, а также из каталога в каталог. В любом из этих случаев создается не новая жесткая связь (связи), а новый файл (фай- лы). При копировании из файла в каталог в последнем создается новая запись, состоящая из простого имени исходного файла и из системного номера нового файла. При копировании из каталога в каталог копируются все файлы (в том числе и подкаталоги) из исходного каталога в конечный каталог. При этом для каждого копируемого файла создается новый файл с точно таким же содержи- 44 мым, после чего новый файл регистрируется в конечном каталоге. Для копиро- вания из каталога в каталог требуется, чтобы был записан флаг –r; б) переименование файлов и их перемещение (в MS-DOS – rename, move): mv исходный_файл (или каталог) конечный_файл (или каталог). Если исходный и конечный файлы находятся в одном и том же каталоге, то данная утилита заменяет имя исходного файла на имя конечного файла. Если же эти файлы находятся в разных каталогах, то производится «перемещение» файла по файловой структуре системы. При этом запись файла в исходном ка- талоге уничтожается, а точно такая же запись в конечном каталоге, наоборот, создается. Если в качестве первого операнда задан файл, а в качестве второго – каталог, то также производится перемещение файла в заданный каталог. Если в качестве обоих операндов заданы имена каталогов, то производится переиме- нование каталога, соответствующего первому операнду; в) создание жестких и символических связей (в MS-DOS – нет): ln исходный_файл файл_ссылка (или каталог).Эта команда создает новую связь с исходным файлом. При отсутствии флага -s создается жесткая связь с этим файлом. В этом случае файл-ссылка представляет собой новое имя уже существующего файла. Если в качестве вто- рого параметра команды задано не имя файла, а имя каталога, то в этом катало- ге исходный файл будет зарегистрирован под своим простым прежним именем. При наличии флага -s создаваемый файл-ссылка представляет собой символи- ческую связь с исходным файлом. 4. Уничтожение файлов и каталогов:а) удаление файлов и каталогов (в MS-DOS – del): rm файлы (или каталог).Эта утилита удаляет не сами файлы, а записи о них в родительских ката- логах. Само удаление файла происходит только в том случае, если число жест- ких связей для этого файла станет равным 0. Если задать флаг -r, то данная команда выполнит удаление заданного ка- талога и всех содержащихся в нем файлов и подкаталогов. Другие флаги:  -f – удаление файлов без запроса подтверждения;  -i – обязательный запрос подтверждения при удалении каждого фай- ла; 45 б) удаление каталогов (в MS-DOS – rmdir): rmdir каталоги.Данная команда может уничтожить каталог только в том случае, если он не содержит файлов и подкаталогов. 5. Работа с текстовой информацией: а) создание новых текстовых файлов и корректировка существующих. Данную функцию выполняют утилиты, называемые текстовыми ре-дакторами. Примеры текстовых редакторов: ed, ее, sed, vi. (Текстовый редактор в MS-DOS – edit.) В качестве примера приве- дем вызов редактораsed: sed [файлы]. Данный редактор редактирует заданные в команде файлы построчно, от меньших номеров строк к большим, без возврата к ранее пройденным стро- кам. Редактирование строк производится согласно командам редактирования, заданным одним из двух способов: 1) в качестве параметров флага -e; 2) команды редактирования содержатся в файле, имя которого задано в качестве параметра флага -f. Если ни одно имя файла в команде не задано, то по умолчанию входным файлом считается клавиатура. Набираемые на ней строки и будут подвергаться редактированию. В этом случае произойдет создание нового текстового файла, который с помощью интерпретатора команд ОС может быть записан на диск; б) вывод текстового файла на экран (в MS-DOS – type): cat [файлы]. Данная утилита выводит на экран содержимое всех текстовых файлов, за- данных в качестве ее параметров. При этом содержимое выводимых файлов на экране никак не разделяется. Если ни один из файлов не задан, то на экран выводится последовательность символов, введенная с клавиатуры (напомним, что клавиатура тоже файл). Ввод с клавиатуры будет выполняться также в том случае, если вместо любого имени файла записан символ «». Для завершения ввода символов с клавиатуры следует одновременно нажать две клавиши: <Ctrl>&<D> («конец файла»); в) сортировка и слияние файлов (в MS-DOS – sort): sort файлы. 46 Если флагов нет, то данная команда выполняет слияние перечисленных файлов в единый файл. Причем строки этого файла сортируются в лексографи- ческом порядке. По умолчанию результат выводится на экран. Два флага этой команды:  -u – при наличии нескольких одинаковых строк результат содержит только одну строку;  -o файл – вывод результата делается не на экран, а в заданный файл; г) вывод текста, вводимого с клавиатуры, на экран и одновременное ко- пирование этого текста в заданный файл (файлы): tee файлы.Один из флагов этой команды:  -a – запись текста не в начало файла (при этом файл создается зано- во), а его добавление в конец существующего файла (файлов); д) вывод строки символов на экран (в MS-DOS – echo): echo строка. Как и командаcd, данная команда выполняется не отдельной утилитой, а подпрограммой интерпретатора команд ОС. 6. Поиск информации:а) поиск файлов (в MS-DOS – find): find каталог [флаги]. Данная утилита осуществляет поиск файлов в поддереве файловой струк- туры, корнем которого является заданный каталог. Условия поиска задаются с помощью флагов. В отличие от ранее перечисленных утилит флаги задаются в конце команды. Из всех многочисленных флагов обратим внимание на два: 1) -type тип – поиск файлов указанного типа. Аргумент тип может принимать следующие значения: b (файл – блочное устройство), c (файл – сим- вольное устройство), d (файл – каталог), f(обычный файл), l(файл – символи- ческая связь), p (файл – именованный канал); 2)-name имя – поиск файлов с указанным именем. В отличие от ранее рассмотренных команд утилита find имеет соб- ственные метасимволы. Метасимвол – символ, имеющий для рассматриваемой программы специальное значение. Метасимволы утилиты findпозволяют за- давать простые имена сразу нескольких искомых файлов в виде всего одного имени. Перечислим эти метасимволы: «*», «?», «[…]». Назначение каждого из 47 этих метасимволов аналогично назначению одноименного метасимвола shell и будет рассмотрено нами позднее. В одной команде find можно задать несколько условий поиска, соеди- нив их при помощи следующих логических операторов:  -a – логическое И;  -o – логическое ИЛИ;  \! – логическое НЕ; б) поиск строк в текстовых файлах (в MS-DOS отсутствует): fgrep подстрока [файлы].Данная утилита осуществляет поиск в перечисленных файлах строк, имеющих в своем составе шаблон  заданную подстроку. Найденные строки выводятся на экран. Если имена файлов опущены, то поиск осуществляется в тексте, вводимом с клавиатуры. При вводе с клавиатуры каждая строка, со- держащая требуемую подстроку, повторяется дважды: первый раз она содер- жит «эхо» вводимых с клавиатуры символов, а второй раз выводится командой fgrep. Некоторые флаги этой команды:  -x – выводятся только строки, полностью совпадающие с шаблоном;  -c – выводится только количество строк, содержащих шаблон;  -i – при поиске не различаются строчные и прописные буквы;  -l – выводятся только имена файлов, содержащих требуемые под- строки;  -n – перед каждой выводимой строкой записывается ее относитель- ный номер в файле. Если задан поиск в нескольких файлах, то перед выводом каждой строки выводится имя соответствующего файла [2]. 7. Выдача справочной информации:а) выдача статистики о текстовых файлах (в MS-DOS отсутствует): wc [файлы].Данная утилита выдает статистику о своих входных файлах. Если эти файлы не заданы, выдается статистика о тексте, введенном с клавиатуры. Флаги этой команды:  -l – вывод числа строк;  -w – вывод числа слов;  -с – вывод числа символов. 48 По умолчанию все три флага установлены (-lwc). Поэтому флаги запи- сываются в этой команде только тогда, когда требуется ограничить выходную статистику; б) вывод и установка даты и времени (в MS-DOS – date,time): date[mmddhhnn[yy]]. Если параметр команды не задан, то на экран выводятся текущие дата и время. Это: день недели, месяц, число, время (час, минуты, секунды), год. Если параметр команды задан, то она выполняет установку текущей даты и времени. При этом параметр команды date включает:  mm – номер месяца;  dd – число;  hh– час (в 24-часовой системе);  nn – минута;  yy – последние две цифры года (необязательная часть параметра ко- манды). Следует отметить, что выполнять установку даты может только супер- пользователь (администратор); в) следующая утилита выводит краткую информацию о системе (в MS-DOS – ver): uname флаги. Значения флагов:  -a – вывод всей доступной информации (объединение всех остальных флагов);  -m – вывод информации об аппаратуре ВС;  -n – вывод имени узла сети;  -p– вывод типа процессора;  -r – вывод главного номера версии ОС;  -s – вывод названия ОС;  -v – вывод дополнительного номера версии ОС; г) выдача справочной информации о пользовательском и программном интерфейсах: man имя, где имя – имя одной из системных программ или подпрограмм, используемое в пользовательских и программных интерфейсах. Сюда относятся имена си- 49 стемных обрабатывающих программ (утилит и лингвистических процессоров), имена системных программных вызовов, а также имена библиотечных функ- ций. Задав имя интересующей вас системной программы, вы можете получить подробные сведения об ее использовании (правда, на английском языке). Например, можно спросить утилиту man о ней самой [1]. 8. Упрощение пользовательского интерфейса. Эту функцию выполняют достаточно сложные утилиты, в названии кото- рых часто присутствует слово commander. Примером такой утилиты для MS-DOS является Norton Commander. Аналогичная утилита для UNIX называ- ется Midnight Commander. (Для того чтобы запустить Midnight Commander, достаточно набрать команду UNIX – mс.) Любая подобная программа предназначена для того, чтобы предоставить пользователю ВСудобный интерфейс для общения с этой системой. Это обес- печивается, во-первых, наглядным выводом на экран информации о файловой структуре системы. Для этого по запросу пользователя утилита переносит с диска на экран информацию, содержащуюся в любом каталоге файловой структуры системы. Во-вторых, любой commander существенно упрощает для пользователя ввод команд ОС за счет того, что он переносит имя исполняемого файла программы из позиции экрана, отмеченной пользователем с помощью псевдокурсора (псевдокурсор – светящийся прямоугольник, получаемый в от- личие от обычного курсора не аппаратно, а программно), в то место памяти, от- куда это имя может взять интерпретатор команд ОС. В отличие от лингвистических процессоров утилиты используются не только программистами, но и пользователями-непрограммистами. Эта наиболее многочисленная категория пользователей ВС работает на вирту- альных машинах, предоставляемых готовыми прикладными программами, а также утилитами. Что касается программистов, то они просто вынуждены ис- пользовать наряду с утилитами еще и лингвистические процессоры. Вспомним, что целью применения любой ВС является выполнение прикладных машинных программ. В следующем разделе рассмотрим применение лингвистических процессоров для получения таких программ. 2.4 Трансляторы Программисты – не самая многочисленная, но очень важная часть поль- зователей ВС. Конечной задачей любого программирования является получе- 50 ние реальной программы, записанной на машинном языке. Только такая про- грамма может быть понята и выполнена центральным процессором. К сожалению, трудоемкость программирования на машинном языке очень ве- лика и не позволяет записывать на нем сколько-нибудь сложные (по решаемым задачам) программы. Решением данной проблемы является предоставление программисту возможности разрабатывать не реальную, а виртуальную при- кладную программу. Виртуальная прикладная программа записывается на языке программи- рования, отличном от языка машинных команд. Преобразование этой програм- мы в реальную программу выполняет системная обрабатывающая программа, называемая лингвистическим процессором. Эта программа (не путать с аппа- ратным процессором) выполняет перевод описания алгоритма с одного языка на другой. Сущность алгоритма при этом сохраняется, но форма его представ- ления, ориентированная на программиста, преобразуется в форму, ориентиро- ванную на ЦП. Лингвистические процессоры делятся на трансляторы и интер- претаторы. В результате работы транслятора алгоритм, записанный на языке программирования (исходная виртуальная программа), преобразуется в алго- ритм, записанный на машинном языке. (На самом деле, как будет показано позже, машинная программа является результатом совместной работы несколь- ких лингвистических процессоров.)Интерпретаторв отличие от транслятора не выдаёт машинную про- грамму целиком. Выполнив перевод очередного оператора исходной програм- мы в соответствующую совокупность машинных команд, интерпретатор обес- печивает их выполнение. Затем преобразуется тот исходный оператор, который должен выполняться следующим по логике алгоритма, и т. д. Интерпретаторы будут рассматриваться нами в следующем параграфе, а сейчас обратимся к трансляторам. В качестве примера рассмотрим преобразование виртуальной программы на языке Си в исполняемый файл для UNIX-системы. Общая схема такого пре- образования приведена на рисунке 2.8. На этой схеме указанное преобразова- ние выполняет цепочка из пяти трансляторов: препроцессор, компилятор, оп- тимизатор, ассемблер и редактор связей. Цепочка из этих последовательно выполняемых трансляторов также является транслятором, выполняющим пре- образование совокупности исходных модулей программы в соответствующий загрузочный модуль. 51 Рис. 2.8  Преобразование исходной программы в загрузочный модуль Исходный модуль программы – текстовый файл, содержащий всю вирту- альную программу или ее часть. Если речь идет о программе на Си, то данный файл имеет имя с суффиксом.c. Любой исходный модуль состоит из операто- ров двух типов – псевдооператоров и исполнительных операторов. Исполни-тельный оператор – оператор исходной программы, преобразуемый в резуль- 52 тате трансляции в машинные команды. При этом исполнительный оператор языка высокого уровня, например языка Си, преобразуется в несколько машин- ных команд. Псевдооператор – оператор исходной программы, представляю- щий собой указание транслятору. В машинные команды этот оператор не транслируется. · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 1   2   3   4   5   6   7   8   9   ...   23

2.5.3 Составные команды В отличие от простой команды составная команда позволяет пользовате- лю запустить не один, а несколько исполняемых файлов. Такая команда пред- ставляет собой или конвейер, или командный список, или многоуровневую ко- манду.Конвейер программ. Имена исполняемых файлов, образующих конвейер, разделяются символом «|». Стандартный вывод программы, стоящей слева от этого символа, одновременно является стандартным вводом для программы, записанной справа. Пример конвейера: $ find dir1 -name a1 | cat > file. В этом примере утилитаfind выводит список файлов с простым именем a1, находящихся в поддереве файловой структуры с корнемdir1(это подка- талог текущего каталога). Причем вывод осуществляется не на экран, а в файл на диске, из которого утилитаcat переписывает имена файлов в файлfile. Программы, образующие конвейер, не конкурируют между собой из-за экрана и клавиатуры, так как клавиатура может быть нужна только первой, а экран – только последней программе конвейера. Поэтому эти программы за- пускаются shellодновременно (асинхронно). После запуска программы, рас- положенные по соседству в конвейере, взаимодействуют между собой через 63 промежуточный файл следующим образом. Программа, для которой этот файл является выходным, помещает в него свои данные построчно (в приведенном примере каждая строка содержит имя файла). Другая программа считывает эти данные также построчно, не дожидаясь завершения работы первой программы. Заметим, что несмотря на то, что промежуточный файл реально существует на диске, его имя неизвестно для пользователя, которому, впрочем, это имя и не нужно. Для того чтобы сохранить промежуточный файл, скопировав его в другой файл, используется команда tee, помещаемая в то место конвейера, где нахо- дится промежуточный файл. Если сравнить конвейер с водопроводной трубой, то эта команда играет роль «тройника» (рис. 2.10). Переделаем предыдущий пример так, чтобы, по-прежнему сохраняя результаты поиска в файлеfile, обеспечить их вывод на экран: $ find dir1 -name a1 | tee file | cat. Рис. 2.10  Наглядное изображение команды teeЕсли первой и последней командам конвейера не нужны соответственно клавиатура и экран (например, благодаря перенаправлению ввода-вывода), то все программы конвейера могут быть запущены в фоновом режиме записью символа «&» в конце конвейера. Подобно тому, как команда запуска программы имеет код завершения, подобный код имеет и конвейер. При этом код завершения конвейера определя- ется кодом завершения программы, записанной в конвейере последней. Командные списки. Такой список образуют конвейеры, разделенные сим- волами: «;», «&», «&&», «||». При этом в качестве конвейеров могут выступать и отдельные исполняемые файлы. Рассмотрим назначение перечисленных сим- волов:  ; – элементы списка, соединяемые этим символом, запускаются по- следовательно. То есть программа (конвейер) справа от символа «;» 64 начинает выполняться только после завершения программы (конвейе- ра) слева. При этом программа слева выполняется в оперативном ре- жиме и поэтому может использовать экран и клавиатуру;  & – элементы списка, соединяемые этим символом, запускаются асин- хронно. При этом программа или конвейер слева от этого символа за- пускается в фоновом режиме;  && – элементы списка, соединяемые этим символом, запускаются по- следовательно. При этом конвейер справа будет запущен только в том случае, если конвейер слева завершился успешно – с нулевым кодом завершения;  || – в отличие от предыдущего случая для запуска конвейера справа требуется неудачное завершение конвейера слева (завершение с нену- левым кодом завершения). Примеры командных списков: 1) $ mkdir dir1; cd dir1; pwd /home/vlad/dir1 2) $ cp -r dir2 dir3 & cat > file1 3) $ mkdir dir1 && cd dir1 4) $mkdir dir1 || echo "Ошибка создания каталога dir1" Многоуровневая команда. Такая команда представляет собой текст одной команды, в которую должны быть подставлены результаты выполнения другой команды или команд. При этом результат вкладываемой команды представляет собой одну или несколько текстовых строк, отображаемых в стандартный вы- вод. Примеры таких команд: pwd, wc, ls, find. Каждая вкладываемая команда должна быть выделена одним из двух способов: а) заключена в обратные апо- строфы «`»; б) заключена в круглые скобки, которым предшествует символ «$». Первый из этих способов применяется, в основном, для двухуровневых команд, а второй – для любого числа уровней вложенности. Shell обрабатывает многоуровневую команду (как и любую другую) слева направо. При этом, встретив очередную вложенную команду, shell обеспечивает ее выполнение, а затем подставляет текст, полученный в резуль- тате этого выполнения, в командную строку. Если данный текст состоит из не- скольких строк, то shell заменяет каждую пару символов «возврат каретки» и 65 «перевод строки», разделяющих соседние строки, на символ пробела. В резуль- тате этого вставляемый текст представляет собой одну большую строку. · · · · · · · · · · · · · · · · · · · · · · · · · Пример · · · · · · · · · · · · · · · · · · · · · · · · · Следующая двухуровневая команда выполняет уничтожение всех файлов и каталогов, простые имена которых начинаются с буквы d и которые располо- жены в поддереве файловой структуры, принадлежащем данному пользователю:$ rm -r ‘find / -name ‘d*’’ · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Обратите внимание, что при задании в команде find имени файла (или каталога) с помощью метасимволов, это имя обязательно должно быть заклю- чено в кавычки (одиночные или двойные). Это объясняется тем, что shell имеет свои метасимволы, одноименные метасимволам утилиты find. Кавычки играют роль «экранирующих» символов, сообщая shell о том, что все симво- лы, заключенные между ними, являются обычными символами, которые долж- ны быть переданы без изменений в запускаемую программу (в данном случае в программу find). Полезно сравнить действие записанной двухуровневой команды с коман- дой: $ rm -r /d*. Последняя команда выполнит уничтожение не всех фай- лов и каталогов с заданным именем в поддереве пользователя, а лишь тех, для которых родительским каталогом является корень этого поддерева. · · · · · · · · · · · · · · · · · · · · · · · · · Пример · · · · · · · · · · · · · · · · · · · · · · · · · Следующая команда имеет 4-уровневую структуру: $ echo 111$(echo 222$(echo 333$(echo 444))) 111222333444 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 2.5.4 Переменные и выраженияКак и любой язык программирования, входной язык ИК позволяет зада- вать переменные. При этом под переменной понимается небольшая область ОП, содержащая данное, которое может быть использовано при выполнении команд shell. В отличие от других языков программирования переменные shell не 66 нуждаются в объявлении типа, так как все они содержат данные одного типа – символьные строки. Имя переменной может включать символы: латинские буквы, цифры, «_». При этом имя не может начинаться с цифры. Как и всегда, для задания значения переменной используется оператор присваивания. В shell это сим- вол «=». Имя присваиваемой переменной помещается слева от этого символа, а справа – новое значение переменной. Для задания этого значения могут быть использованы следующие способы. Непосредственное задание строки символов. Если эта строка состоит из одного слова, то ее можно не выделять. Для задания строки из нескольких слов обязательны двойные кавычки. · · · · · · · · · · · · · · · · · · · · · · · · · Пример · · · · · · · · · · · · · · · · · · · · · · · · · $ var1=/home/vlad/a.txt $ var2="/home/vlad/a.txt" · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · В результате выполнения этих операторов переменныеvar1 иvar2 имеют одинаковое значение. Задание значения другой переменной. Для этого перед именем перемен- ной в правой части оператора присваивания должен быть помещен символ «$». · · · · · · · · · · · · · · · · · · · · · · · · · Пример · · · · · · · · · · · · · · · · · · · · · · · · · $ var1=/home/vlad/a.txt $ var2=$var1 $ echo $var2 /home/vlad/a.txt · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · В этом примере значение переменнойvar1 используется для задания значения переменной var2. А значениеvar2 используется в качестве пара- метра командыecho. Использование выходных данных команды shell. Оно выполняется точ- но так же, как и в многоуровневой команде (см. пп. 2.5.3). При этом имя любой программы, которая выдает свой результат в виде одной или нескольких строк символов, может быть записано справа от оператора присваивания, заключен- 67 ным в обратные апострофы «`», или может быть заключено в круглые скобки, которым предшествует символ «$».Shell сначала запускает указанную про- грамму на выполнение, а затем подставляет ее выходные данные в качестве значения заданной переменной. · · · · · · · · · · · · · · · · · · · · · · · · · Пример · · · · · · · · · · · · · · · · · · · · · · · · · $ var=`pwd` · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · В данном примере shell сначала запустит на выполнение утилитуpwd, которая выдаст имя текущего каталога, затем подставит это имя в качестве зна- чения переменной var. Использование команды ввода read. Оно позволяет ввести значения пе- ременных со стандартного ввода (с клавиатуры), не используя оператор при- сваивания. Для этого имена определяемых переменных должны быть перечис- лены в качестве параметров этой команды. Вводимые далее с клавиатуры (до нажатия ) слова распределяются между переменными так, что в одну переменную записывается одно слово. Если число переменных меньше числа слов в введенной строке, то все оставшиеся слова записываются в последнюю переменную. Если, наоборот, число переменных больше, то последние пере- менные получат пустое значение. Если с клавиатуры вместо обычных символов будет введен символ конца файла (>&<D>), то данная команда завершит- ся с ненулевым кодом завершения. Команду read удобно использовать для того, чтобы присваивать пере- менным значения слов из некоторого текстового файла. Для этого достаточно перенаправить стандартный ввод с клавиатуры на ввод из требуемого файла. Например, следующая команда присваивает переменным x, y, z значения слов из первой строки файла file: $ read x y z < file Таким образом, для того, чтобы определить обыкновенную переменную, достаточно хотя бы раз записать ее имя слева от оператора присваивания или записать его в качестве параметра команды read. После этого до конца вашей работы с данным shell значение данной переменной может использоваться в любом месте любой команды. Для этого имени переменной должен предше- ствовать символ «$», смысл которого в данном случае есть «значение перемен- 68 ной». Выше приведены примеры использования значения переменной в правой части оператора присваивания, а также в качестве параметра команды echo. Если имя переменной следует отделить от символов, записанных сразу за ним, то это имя следует заключить в символы «{» и «}». · · · · · · · · · · · · · · · · · · · · · · · · · Пример · · · · · · · · · · · · · · · · · · · · · · · · · $ var=abc $ echo $varxy $ echo ${var}xy abcxy · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · В данном примере в качестве параметра первого оператора echoзаписа- но значение неопределенной ранее переменной varxy. В подобных случаях shell подставляет вместо неопределенной переменной пустое место. Второй операторecho получает в качестве своего параметра значение переменной var(символы abc), к которому «подсоединены» символы xy. Используя утилиту set (без параметров), можно вывести на экран пере- чень переменных, определенных в данном сеансе работы с shell, а также их значения. В состав данных переменных входят не только обыкновенные пере- менные, заданные операторами присваивания, но и переменные окружения – переменные, которые shell «наследует» от программы, запустившей его. (В гл. 3 будет показано, что любая обрабатывающая программа имеет «роди- тельскую программу».) Рассмотрим некоторые переменные окружения: 1) HOME – содержит полное имя корневого каталога пользователя; 2) PATH – содержит перечень абсолютных имен каталогов, в которых shell выполняет поиск исполняемого файла в том случае, если для его задания в своей команде пользователь использовал простое имя файла. Имена-пути каталогов, записанные в данной переменной, раз- деляются символом «:». Следует отметить, что shell не производит поиск исполняемого файла в текущем каталоге по умолчанию, и для этого требуется явное задание текущего каталога в переменной PATH (для этого используются символы «./»). Кроме того, заметим, что shell не использует данную переменную для поиска неисполняе- мых, например текстовых, файлов. Поэтому для задания таких файлов 69 в команде пользователя требуется или использовать их абсолютные имена, или обеспечить перед выполнением такой команды переход в родительский каталог файла; 3) PS1 – приглашение shell в командной строке (обычно – $); 4) PS2 – вторичное приглашение shell в командной строке (обычно – >). Выводится на экран в том случае, когда вводимая команда пользо- вателя занимает более одной строки. Используя оператор присваивания, можно заменить содержимое пере- менной окружения подобно тому, как это делается для обыкновенных перемен- ных. Например, следующая команда добавляет в переменную PATHимя теку- щего каталога: $ PATH=${PATH}":./". Изменение переменной окружения приведет к тому, что не только теку- щая программа shell, но и все запущенные ею программы будут использовать новое значение данной переменной. В то же время программы, являющиеся «предками» данного shell, по-прежнему будут работать с ее прежним значе- нием. Обыкновенные переменные можно добавить к переменным окружения, сделав их «наследуемыми». Для этого достаточно перечислить имена этих пе- ременных в качестве параметров команды export. Подобно другим языкам программирования, входной язык shellпозво- ляет записывать выражения. · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Выражение – совокупность нескольких переменных и (или) констант, соединенных знаками операций. Различают арифмети-ческие и логические выражения. · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Арифметические выражения имеют при программировании для shell весьма ограниченное значение. Вспомним, что данный язык даже не имеет арифметических типов данных. Если все-таки требуется выполнить над пере- менными shell арифметические действия, то для этого следует использовать команду (функцию shell) expr. · · · · · · · · · · · · · · · · · · · · · · · · · Пример · · · · · · · · · · · · · · · · · · · · · · · · · $ expr 5 + 3 8 70 $ expr 5 "*" 3 15 $ x=10 $ expr $x + 1 11 $ x=20 $ x=`expr $x + 2` $ echo $x 22 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Заключение в кавычки знака умножения обусловлено тем, что данный символ является для shell метасимволом, и поэтому для устранения его спе- циальных свойств он должен быть «экранирован». Обратите внимание, что зна- ки арифметических операций должны быть окружены пробелами. · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Логическое выражение – выражение, имеющее только два значения – 0 (истина) и 1 (ложь). · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Операндами логического выражения являются операции отношения, каждая из которых или проверяет отношение файла (или строки символов) к заданному свойству, или сравнивает между собой два заданных числа (или две строки символов). Если проверяемое отношение выполняется, то результа- том операции отношения является 0, иначе – 1. Перечислим некоторые из опе- раций отношения: -s file размер файла file больше 0 -r file для файла file разрешен доступ на чтение -w file для файла file разрешен доступ на запись -x file для файла file разрешено выполнение -f file файл file существует и является обычным файлом -d file файл file существует и является каталогом -z string строка string имеет нулевую длину -n string строка string имеет ненулевую длину string1 = string2 две строки идентичны string1 != две строки различны 71 string2 i1 -eq i2 число i1 равно числу i2 i1 -ne i2 число i1 не равно числу i2 i1 -lt i2 число i1 строго меньше числа i2 i1 -lе i2 число i1 меньше или равно числу i2i1 -gt i2 число i1 строго больше числа i2 i1 -gе i2 число i1 больше или равно числу i2При записи логического выражения отдельные операции отношения мо- гут соединяться друг с другом с помощью логических операций:  ! – логическое отрицание;  -a – логическое И;  -o – логическое ИЛИ. При этом наибольший приоритет имеет операция !, а наименьший – -o. Приоритеты операций определяют порядок их выполнения. Порядок вы- полнения логических операций можно изменить, используя круглые скобки. Для shell характерно то, что запись логического выражения еще не означает его автоматического вычисления. Для этого требуется, чтобы элемен- ты логического выражения были записаны в качестве параметров команды test. Результатом выполнения этой команды является код завершения: 0 – ло- гическое выражение истинно, 1 – ложно. Команду testможно задать одним из двух способов: 1) обычным способом; 2) заключив логическое выражение в квадратные скобки. · · · · · · · · · · · · · · · · · · · · · · · · · Пример · · · · · · · · · · · · · · · · · · · · · · · · · $ var1 = 10; var2 = 20; var3 = 30 1) $ test $var1 –gt $var2 && echo "var1 > var2" 2) $ [ $var1 –gt $var2 ] || echo "var1 <= var2" var1 <= var2 3) $ test $var1 = $var2 && echo "var1 = var2" 4) $ [ $var1 = $var2 –o $var2 != $var3 ] && echo "====" ==== 5) $ test \($var1 –eq $var2 \) && echo "var1 = var2" 6) $ [ ! \($var1 –eq 0 \) ] && echo "var1 не равно 0" 72 var1 не равно 0 7) $ test \($ var1 != $var2 \) –a \($var1 –eq $var2 \) || echo "????" ????8) $ [ abc ] && echo true true · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · В примерах 1 и 2 операции отношения сравнивают численные значения переменных. В зависимости от этих значений выводятся соответствующие со- общения на экран. В примере 2 команда test задается с помощью квадратных скобок, которые обязательно отделяются от логического выражения пробелами. В примерах 3 и 4 содержимое каждой переменной рассматривается не как число, а как строка символов. Обратите внимание, что операция проверки идентичности строк (=) в отличие от операции присваивания выделяется с обе- их сторон пробелами. В примерах 5, 6 и 7 для выделения логического выражения или его частей используются круглые скобки. При записи каждой круглой скобки должны быть выполнены два требования: 1) непосредственно перед скобкой должен быть помещен символ «\»; 2) перед символом «\» и после скобки обязательно должны быть записаны пробелы. Наличие первого требования обусловлено тем, что круглые скобки рассматриваются интерпретатором shellкак слу- жебные символы. Для того, чтобы эти скобки не выполняли свои служебные функции, а были переданы без изменений в подпрограмму, выполняющую ко- манду test, они должны быть «экранированы». Такое «экранирование» и вы- полняет символ «\». Интересно отметить, что в примере 7 операции отношения (записаны в круглых скобках) всегда дают противоположный результат. При этом в первой из них переменные сравниваются как строки символов, а во вто- рой рассматриваются их численные значения. Пример 8 иллюстрирует тот факт, что команда testвыдает значение 0 (истина), если вместо логического выражения записано любое непустое слово. Во всех приведенных выше примерах команда test, выполняющая вы- числение логического выражения, записывается в качестве первой команды командного списка, управляя выполнением второй команды этого списка. Дру- гим применением этой команды являются управляющие операторы shell. 73 1   2   3   4   5   6   7   8   9   10   ...   23

2.5.5 Управляющие операторы Как и любой алгоритмический язык программирования, входной язык shellимеет управляющие операторы. Данные операторы предназначены для того, чтобы задавать порядок выполнения простых и составных команд. Рас- смотрим эти управляющие операторы. 1. Условный оператор if позволяет выполнить одну из нескольких вза- имоисключающих последовательностей команд shell. Данный оператор име- ет несколько форм записи, наиболее простая из которых следующая: ifкоманда-условие then последовательность команд fiРабота данного оператора начинается с выполнения команды-условия. Это может быть любая простая или составная команда, имеющая код заверше- ния. Но чаще всего в качестве этой команды используют команду test, вы- числяющую логическое выражение. Если при выполнении данной команды по- лучен нулевой код завершения (напомним, что такой код соответствует успешному завершению программы или значению «истина» логического выра- жения), то далее выполняется последовательность команд, записанная после ключевого слова then. При получении ненулевого кода завершения команды- условия выполнение условного оператора завершается без выполнения каких- либо действий. Форма оператора if, предполагающая выполнение одной из двух после- довательностей команд: ifкоманда-условие then последовательность команд 1else последовательность команд 2fi · · · · · · · · · · · · · · · · · · · · · · · · · Пример · · · · · · · · · · · · · · · · · · · · · · · · · Допустим, что переменная dir содержит простое имя каталога. Тогда следующая совокупность команд выполняет уничтожение каталога в том слу- 74 чае, если он пуст, в противном случае выполняется его переименование добав- лением к простому прежнему имени символа «a»: $ ls $dir > fil1 $ if [ -s fil1 ] > then > mv $dir a$dir > else > rmdir $dir > fi · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · В данном примере содержимое заданного каталога помещается во вспо- могательный файл fil1. Если длина этого файла ненулевая, то каталог пере- именовывается, иначе – уничтожается. Наиболее общая структура условного оператора: ifкоманда-условие 1then последовательность команд 1elifкоманда-условие 2последовательность команд 2 elif else последовательность команд Nfi Если был получен ненулевой код завершения команды-условия 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}/k2done& · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Обратите внимание, что для задания корневого каталога поддерева поль- зователя используется не символ «», а переменная окружения 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}/$2done<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

6.3.2 Распределение памяти Как следует из п. 6.2, аппаратура управления сегментами обеспечивает два свойства линейных виртуальных адресов: 1) каждый такой адрес не может быть больше 4 Гбайт; 2) любой виртуальный сегмент отображается на непре- рывный участок линейной памяти. С учетом этих свойств сохраняется большая свобода выбора начальных линейных адресов сегментов, записываемых ОС в дескрипторы сегментов (поле В на рисунках 6.3–6.5). Эти адреса выбираются ОС следующим образом. Во-первых, программа каждого процесса «загружается» в собственную линейную виртуальную память размером 4 Гбайта. · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Линейная виртуальная память (ЛВП) – абстракция, ис-пользуемая не самой программой (она работает с сегментной вир-туальной памятью), а операционной системой. · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Во-вторых, в эту ЛВП «загружается» и сама ОС. В UNIX используется распределение линейной виртуальной памяти процесса, изображенное на ри- сунке 6.12. При этом 3 Гбайта с меньшими адресами отводятся самой приклад- ной программе, а 1 Гбайт с большими адресами – для ядра ОС. Причем систем- ные DLL обычно располагаются вверху прикладной части ЛВП. Рис. 6.12  Отображение линейной виртуальной памяти на реальную ОП 175 В-третьих, если в ходе выполнения процесса ему понадобится дополни- тельная ОП, то запрашиваемый объем будет выделен ОС из подходящей сво- бодной области ЛВП динамически. · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Всякое назначение памяти процессу, осуществляемое в ходе его выполнения, называется динамическим распределением па-мяти. Статическое распределение – память выделяется при со-здании процесса. · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · В-четвертых, ОС выполняет «загрузку» сегментов процесса в ЛВП путем записи начального линейного виртуального адреса каждого сегмента в его де- скриптор. При этом сегменты ядра (их дескрипторы находятся в GDT) всегда «загружены» в ЛВП по одним и тем же адресам. В-пятых, содержимое ЛВП используется ОС для выполнения записей в каталог таблиц страниц и в сами таблицы страниц (инициализация таблиц). Один каталог страниц обычно используется для адресации памяти одного про- цесса. При этом из 1 024 строк каталога 256 строк соответствуют ОС, а 768 строк – прикладной программе. (При смене на ЦП выполняемого процес- са 256 строк в каталоге не меняются, а заменяются лишь 768 строк.) Если 4 Мбайта ЛВП, соответствующие данной строке каталога, содержат какую-то информацию, то в эту строку ОС помещает указатель на соответствующую таб- лицу страниц. Иначе – строка каталога содержит пустой указатель. Таблица страниц, соответствующая непустой строке каталога, может со- держать до 1 024 строк, каждая из которых содержит дескриптор одной логиче- ской страницы программы. Так как объем одной страницы составляет 4 096 байтов, то максимальный объем ЛВП, соответствующий одной таблице страниц, составляет 4 Мбайта. Любая часть этого объема может соответство- вать «пустым» страницам. Так как ОС ведет учет распределения ЛВП, то «пу- стые» страницы ей известны, и она не создает для них дескрипторы в таблице страниц. Естественно, что при создании процесса ОС распределяет ему не только ЛВП, но и реальную ОП. Не предоставив процессу хотя бы небольшое число физических страниц, нельзя обеспечить его выполнение. При этом системная часть программы процесса (256 строк в каталоге таблиц страниц) всегда отоб- ражается на одну и ту же часть реальной ОП (с меньшими адресами). А при- кладная часть ЛВП отображается на ту совокупность физических страниц, ко- 176 торые ОС выделила процессу. Страничное распределение ОП обладает тем су- щественным достоинством, что вследствие одинаковой длины страниц любая логическая страница может быть загружена в любую физическую страницу. Поэтому не только страницы процесса, но и страницы логического сегмента не образуют непрерывный раздел ОП, а располагаются в произвольных местах памяти. Благодаря свопингу страниц число логических страниц процесса может быть значительно больше, чем выделенное ему число физических страниц. Для организации такого свопинга аппаратура процессора i80386 предоставляет в помощь ОС исключение отказ страницы, а также специальные биты в де- скрипторах страниц, аналогичные соответствующим битам в дескрипторе таб- лицы страниц (см. рис. 6.7): 1) P – бит присутствия страницы в памяти (1 – страница в ОП; 0 – нет); 2) бит D – устанавливается в 1, если была выполнена запись в страницу; 3) AVL – три бита, которые ОС может использовать по своему усмотре- нию. Совместная работа аппаратуры и ядра ОС при реализации страничного свопинга заключается в следующем. Выполнив разделение очередного вирту- ального линейного адреса, аппаратура ЦП проверяет бит P в искомом дескрип- торе страницы. Если P 1, то выполнение программы продолжается, иначе – возникает исключение «отказ страницы». Его обработчик подкачивает требуе- мую страницу из ВП. Обычно страница загружается на место ранее загруженной страницы, ко- торая или копируется из ОП на диск (если бит D 1), или нет (бит D 0). Для определения откачиваемой страницы могут использоваться различные крите- рии. Например, в качестве такой страницы может быть выбрана та, к которой было сделано наименьшее число обращений. В качестве счетчика числа обра- щений может быть использовано поле AVL дескриптора страницы. Распределение ОП, основанное на страничном свопинге, обладает тем существенным достоинством по сравнению с сегментным свопингом, что вследствие одинаковой длины страниц размещение одной страницы в ОП мо- жет быть выполнено вместо любой другой. Поэтому при размещении в памяти новой страницы не требуется выполнять каких-либо перемещений ранее загру- женных страниц. Что касается защиты информации в ОП, то аппаратура управления стра- ницами в i80386 предоставляет для этого единственное средство: при выполне- 177 нии любой машинной команды, выполняющей запись в ОП, аппаратно прове- ряется бит W в дескрипторе той страницы, в которую выполняется запись. При W 1 команда записи производится, а при W 0 возникает исключение. Эффек- тивность данного средства существенно ниже защитных действий, выполняе- мых аппаратурой управления сегментами (см. пп. 6.2.3). · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · Контрольные вопросы по главе 6 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 1. Используется ли регистр CS для защиты информации в ОП? 2. Используется ли дескриптор сегмента процесса для защиты информа- ции в ОП? 3. Используется ли регистр EAX для защиты информации в ОП? 4. Как определить реальный адрес первой ячейки сегмента ОП? 5. Используется ли дескриптор таблицы страниц при страничном управ- лении ОП? 178 7 Управление файлами 7.1 Виртуальная файловая система 7.1.1 Логические файлы Файловая подсистема ОС предназначена для обслуживания процессов по информационному обмену с периферийными устройствами, прежде всего с устройствами ВП. В UNIXэта подсистема является частью ядра ОС (см. п. 4.3) и имеет укрупненную структуру, приведенную на рисунке 7.1. Как видно из данного рисунка, файловая подсистема включает виртуальную файло- вую систему, программные части реальных файловых систем, а также кэш. Рис. 7.1  Структура файловой подсистемы ОС 179 В п. 2.2 мы рассмотрели файлы и файловую структуру системы с точки зрения пользователя. Теперь расширим эти представления до уровня, использу- емого в программах процессов. Так как программисты являются частным слу- чаем пользователей, то такое расширение является вполне обоснованным. Заметим, что программа процесса имеет дело не с реальным, а с логиче- ским файлом. В отличие от реального файла, представляющего собой уникаль- но поименованную битовую строку на конкретном носителе, логический файл не связан с конкретным носителем информации, а его программное имя не яв- ляется уникальным в пределах всей системы. Несмотря на то что и физический, и соответствующий ему логический файл содержат одну и ту же битовую строку, разбиение этой строки на записи в обоих файлах различно. В то время как записи физического файла выбирают- ся исходя из удобства их размещения на носителе, разбиение логического фай- ла на записи производится по смысловому признаку. Например, если логиче- ский файл содержит сведения о сотрудниках какой-то организации, то одна запись такогофайла содержит информацию об одном сотруднике. Многие прежние ОС поддерживали разбиение логических файлов на ло- гические записи. В результате программа могла, например, выполнить чтение или запись логической записи, используя для ее идентификации или номер за- писи в файле, или ее ключ (здесь ключ – символьное имя записи). Современные ОС, в том числе UNIX, не поддерживают разбиение логических файлов на за- писи. Они позволяют программе работать с логическим файлом так, как с длинной последовательностью байтов. Естественно, что разбиение логического файла на записи есть. Но это разбиение известно только самой обрабатываю- щей программе. Для ОС оно не известно, и ее информационное общение с про- граммой сводится к обмену между ними цепочками байтов, которые ОС или помещает в файл, или считывает из него. В п. 2.2 была рассмотрена файловая структура системы, объединяющая в единое целое все файлы системы. (Напомним, что для UNIX файловая струк- тура представляет собой единое дерево.) С учетом того что нигде в системе данная структура целиком не хранится, будем называть ее логической файловой структурой. Если считать, что элементами логической файловой структуры являются логические файлы, то получим логическую файловую систему – пред- ставление совокупности файлов с точки зрения пользователя-программиста. Заметим, что термин «файловая система» является общепринятым, но не однозначным. Точно так же принято называть совокупность подпрограмм, вы- 180 полняющих обработку соответствующих файлов. Во избежание путаницы бу- дем называть ту совокупность подпрограмм, которая выполняет обработку ло- гических файлов, виртуальной файловой системой (ФС). После того как интерфейс системных вызовов выполнит «техническую» подготовку поступившего в ядро системного вызова, виртуальная ФС присту- пает к его действительному выполнению. Наличие этой подсистемы позволяет использовать в программах процессов стандартную совокупность системных вызовов для обработки файлов, не зависимую ни от физической реализации файлов, ни от физической реализации соответствующей файловой системы. 7.1.2 Открытие файла Наиболее интересным системным вызовом, выполняемым виртуальной файловой системой, является открытие файла. Данный системный вызов вы- полняет связывание физического файла на ПУ с его логическим заменителем. При этом для получения такой связи используются почти все управляющие структуры данных виртуальной файловой системы. Для открытия существующего файла программа процесса должна содер- жать системный вызов: ОТКРЫТЬ_ФАЙЛ (If,r || i), (на Си – open), гдеIf– символьное имя файла одного из трех типов (простое, относительное или абсолютное), рассмотренных в п. 2.2. Это имя используется для идентификации физического файла, задавая его расположение в логи- ческой файловой структуре; r – требуемый режим работы с файлом (чтение, запись, чтение и запись, добавление в конец файла);i– программное имя (номер) файла, уникальное для данного процесса. Это имя логического файла, которое может использоваться далее програм- мой процесса для выполнения операций с этим файлом. Получив данный системный вызов, виртуальная файловая система ищет требуемый файл, обращаясь за помощью к реальной файловой системе. По- дробно реальные файловые системы рассматриваются в п. 7.2, а пока лишь за- метим, что основной функцией такой системы является выполнение операций с физическими файлами. Кроме того, в данном разделе мы не будем обращать особого внимания на тот факт, что в любой ФС существует не одна, а несколь- ко реальных файловых систем. К этому вопросу мы вернемся в п. 7.3. 181 В зависимости от заданного символьного имени файла виртуальная ФС начинает поиск требуемого файла с анализа, или корневого каталога системы (задано абсолютное имя файла), или корневого каталога данного пользователя (относительное имя файла начинается с символа «»), или текущего каталога данного пользователя (простое или относительное имя файла). При этом имена текущего каталога и корневого каталога данного пользователя берутся из соот- ветствующих полей в структуре user, входящей в состав дескриптора процес- са (см. п. 5.2). В любом случае поиск искомого файла начинается с анализа того vnode, который соответствует исходному каталогу. Vnode (от virtual inode – виртуальный индексный дескриптор) – часть де- скриптора файла, содержащая ту информацию о реальном файле, состав кото- рой универсален для любого типа файлов. Перечислим наиболее интересные поля vnode: 1) число ссылок на данный vnode. Это суммарное число открытий фай- ла во всех процессах на данный момент времени; 2) указатель на тот элемент списка монтирования (рассматривается в п. 7.3), который соответствует реальной файловой системе, содер- жащей искомый физический файл; 3) указатель на тот элемент списка монтирования, который соответству- ет подключенной реальной ФС (если vnode соответствует каталогу, который является точкой монтирования); 4) номер реального дескриптора файла – inode. Подробно inode рас- сматриваются в п. 7.2, а пока лишь заметим, что это вторая часть де- скриптора файла (первая – vnode) и что в любой информационной части реальной ФС все inode пронумерованы. Номер inode являет- ся уникальным числом в пределах данной информационной части ре- альной ФС; 5) указатель на inode в таблице активных inode, расположенной в ОП. Эта таблица принадлежит реальной ФС и содержит только те inode, которые соответствуют файлам, открытым хотя бы в одном процессе; 6) указатель на перечень операций, который может выполняться над данным vnode. Состав этих операций стандартный. Но фактическая реализация каждой такой операции зависит от типа реальной ФС, в которой находится соответствующий физический файл. Поэтому 182 данное поле содержит указатель на массив других указателей, каждый из которых представляет собой начальный адрес той процедуры ре- альной ФС, которая выполняет соответствующую операцию над фи- зическим файлом; 7) тип файла, которому соответствует данный vnode: обычный файл, каталог, специальный файл устройства, символическая связь, удален- ный файл. Обратим внимание на поле 2, содержащее указатель на реальную ФС в списке монтирования, и поле 4, содержащее номер inodeв реальной ФС. Пара этих чисел является уникальным системным именем файла на данный момент времени. Другим уникальным системным именем файла является номер самого vnode в таблице vnode (рис. 7.2). Размер этой таблицы определяет максимальное число файлов, которые могут быть открыты в системе. При этом каждому открытому файлу соответствует один vnode, независимо от того, в скольких процессах сколько раз был открыт данный файл. Данное имя файла обеспечивает быстрый доступ к содержимому vnode файла, но оно является временным: после того, как файл будет закрыт во всех процессах, соответству- ющий vnode будет освобожден и может быть выделен другому файлу. В отли- чие от него рассмотренное ранее системное имя файла (указатель на реальную ФС в списке монтирования и номер inode) является более долговременным и может использоваться для идентификации файла до тех пор, пока данная ре- альная ФС (информационная часть) не будет отсоединена от файловой структу- ры системы. Определив из vnode исходного каталога его системное имя (указатель на реальную ФС в списке монтирования и номер inode), виртуальная ФС ис- пользует это системное имя каталога, а также символьное имя искомого файла в качестве входных параметров при вызове процедуры реальной ФС. Эта про- цедура выполняет трансляцию имени файла – получение на основе символьно- го имени файла его системного имени (указатель на реальную ФС в списке монтирования и номер inode). Заметим, что это одна из тех процедур реаль- ной ФС, доступ к которой выполняется с помощью указателя на перечень опе- раций, расположенного в поле vnode. Сама трансляция имени сводится к по- шаговому «движению» по цепочке каталогов до тех пор, пока или не будет достигнут требуемый файл, или при прохождении очередного каталога будет выяснено, что права доступа к нему данного пользователя не отвечают мини- 183 мально необходимым требованиям (см. п. 4.2). Так как каталог является разно- видностью файла, то для его просмотра также требуется выполнить операцию «открытие файла». Но в отличие от открытия обычного файла открытие катало- га выполняется в рамках ядра и скрыто от прикладной программы, выдавшей системный запрос. Рис. 7.2  Системные структуры данных для доступа процессов к файлам 184 Если при чтении последнего каталога, заданного в символьном имени файла, будет найдено искомое простое имя файла, то процедура трансляции имени возвратит в виртуальную ФС системное имя файла (указатель на реаль- ную ФС в списке монтирования и номер inode). Далее виртуальная ФС ис- пользует это системное имя файла для поиска его vnode в своей таблице. Если требуемый vnode обнаружен, то число ссылок в его соответствую- щем поле увеличивается на единицу. Если виртуальная ФС не обнаружила vnode открываемого файла в своей таблице, то она создает новый vnode. Для этого ищется первый свободный элемент в таблице vnode, и его порядковый номер становится номером нового vnode. При заполнении полей этого vnode виртуальная ФС использует информацию, возвращенную ей процедурой реаль- ной ФС. После того как vnode открываемого файла или найден, или создан зано- во, виртуальная ФС добавляет новую запись в свою системную файловую таб-лицу. Каждый процесс имеет в этой таблице свои записи, каждая из которых со- ответствует одному открытому процессом файлу. Если один и тот же файл открыт процессом несколько раз, то каждому открытию соответствует своя за- пись в системной файловой таблице. Перечислим поля этой записи: 1) режим доступа к файлу (чтение, запись, чтение и запись, добавление в конец файла); 2) текущее значение файлового указателя – номер байта файла, начиная с которого будет выполняться следующая операция информационного обмена с файлом (чтение или запись). Сразу после открытия файла эта переменная указывает в зависимости от режима открытия на самый первый или самый последний байт файла; 3) указатель на vnode файла. Далее виртуальная ФС находит первую свободную строку в таблице от-крытых файлов процесса, являющейся частью структуры user процесса, а за- тем заполняет эту строку. Данная строка имеет всего два поля: указатель на со- ответствующую строку в системной файловой таблице и флаг наследования открытого файла. Если этот флаг установлен, то при создании дочернего про- цесса (с помощью соответствующего системного вызова) данный файл закры- вается и его номер не наследуется дочерним процессом. После того как строка в таблице открытых файлов процесса заполнена, ее номер i возвращается системным вызовом в прикладную программу процесса в 185 качестве программного имени открытого файла. Это имя действует в пределах данного процесса, а также наследуется (если это не запрещено флагом наследо- вания) его дочерними процессами. Использование для открытия файла строки таблицы открытых файлов процесса с наименьшим номером нашло применение, в частности, для перена- правления ввода-вывода. Например, если пользователь запустил с командной строки какую-то программу, указав при этом замену стандартного вывода (то есть экрана) на какой-то файл, то процесс-shell, выполняющий обработку этой команды, во-первых, закроет файл с программным именем 0. Во-вторых, он откроет заданный файл. При открытии файла будет выбран свободный эле- мент таблицы открытых файлов процесса с наименьшим номером, то есть с но- мером 0. Так как структура user, включающая таблицу открытых файлов про- цесса, наследуется дочерним процессом, то весь его вывод на экран будет записан в требуемый файл. Естественно, что процесс-shell после запуска но- вого процесса должен «восстановить справедливость», закрыв файл и открыв экран. Заметим, что многие файлы, которые shell открывает для себя, не предназначены для использования в дочерних процессах. Для таких файлов выполняется установка флага наследования. На рисунке 7.2 один и тот же файл U открыт и в процессе 1, и в процес- се 2. Причем в процессе 1 он открыт дважды: под именем 1 и под именем 3. 1   ...   13   14   15   16   17   18   19   20   ...   23


57 батывающие программы, зная лишь имя соответствующего исполняемого фай- ла. Речь идет об интерпретаторе команд ОС.
2.5 Язык управления операционной системой
2.5.1 Общие сведения
Любая операционная система предоставляет своему пользователю (поль- зователям) возможность управлять своей работой. Поэтому язык управления
ОС является обязательной частью интерфейса между пользователем и ВС. Су- ществуют два основных типа таких языков.
Первый тип языка управления ОС ориентирован на работу системы с не- подготовленным пользователем и заключается в использовании меню: в любой момент времени пользователь видит на экране набор доступных команд, из ко- торых он должен сделать выбор. Такой подход реализован в различных Win- dows. В этих системах используется графическое меню: на экране представле- ны значки, соответствующие исполняемым файлам, файлам данных, а также каталогам (папкам). Пользователь сообщает о своем выборе в «меню», наведя курсор мыши, а затем нажав на ее клавишу. При выборе исполняемого файла
(расширение имени файла – com, exe или bat) ОС запускает на выполнение соответствующую программу или программы (для bat-файла). Выбор файла данных означает, что на исполнение должна быть запущена системная утилита, выполняющая обработку данного файла. Выбор каталога приводит к выводу на экран меню, состоящего из файлов и подкаталогов этого каталога.
Второй тип языков управления ОС – языки команд. Каждый такой язык ориентирован на подготовленного пользователя, знакомого с языком команд.
Набрав на клавиатуре свою команду, пользователь нажимает клавишу , сообщая тем самым системе, что она может приступать к выполнению коман- ды. Такой подход используется в операционных системах MS-DOS и UNIX.
Любой из подходов к организации пользовательского интерфейса пред- полагает, что обработку команд управления ОС выполняет ее модуль, называе- мый интерпретатором команд ОС (сокращенно ИК). Как и любой интерпрета- тор, данная программа выполняет обработку поступающих на ее вход команд по одной, запуская на выполнение требуемую машинную программу или под- программу. Являясь для пользователя частью ОС, ИК рассматривается основ- ной частью этой системы (ядром ОС) как обычная обрабатывающая программа.


58
Следствием этого является то, что ИК размещается в отдельном исполняемом файле. Для MS-DOS это command.com, а в любой UNIX-системе существует несколько взаимозаменяемых ИК. Наиболее известные из них: Bourne shell
– файл /bin/sh, C shell/bin/csh, Korn shell – /bin/ksh,
Bourne-Again shell/bin/bash. Все эти ИК имеют общее название – shell
. В качестве примера далее рассматривается язык команд для наиболее типичного shell – Bourne shell.
После входа пользователя в систему и запуска первоначального shell
(эти операции будут рассмотрены в п. 4.1) на экран выводится приглашение ввести следующую команду. Часто в качестве такого приглашения использует- ся символ «$». В ответ пользователь набирает команду одного из следующих типов:
1) простая команда;
2) составная команда;
3) вызов подпрограммы на языке shell;
4) управляющий оператор;
5) командный файл.
Пользователи-непрограммисты обычно ограничиваются первыми двумя типами команд, так как применение остальных типов команд фактически озна- чает программирование на языке команд shell.
2.5.2 Простые команды
Простые команды shellделятся на команды: а) запуска программ; б) команды вызова функций shell; в) вспомогательные команды. Последняя из перечисленных групп команд будет рассмотрена нами в пп. 2.5.4 при рас- смотрении переменных shell.
Первые две группы команд, которые мы будем сейчас рассматривать, различаются по реализации: команда запуска программы требует от shell обеспечить выполнение какой-то обрабатывающей программы (прикладной, утилиты или лингвистического процессора), а команда вызова функции shell запускает внутреннюю подпрограмму самого shell. С точки зрения пользова- теля ВС эти два типа команд почти не различимы. Единственное различие: ко- манда запуска программы имеет, а команда вызова функции shell не имеет кода завершения. Код завершения – целое неотрицательное число: 0 – запу-

59 щенная программа завершилась успешно; > 0 – программа завершилась с ошибкой.
Так как число исполняемых файлов практически не ограничено, то и не ограничено число простых команд запуска программ. По своей форме наиболее распространенная команда shell представляет собой имя исполняемого файла прикладной или системной обрабатывающей программы, за которым через раз- делитель (символ пробела) записаны параметры команды. Пример команды:
$ cat abc.txt.
Эта команда выведет на экран содержимое файла abc.txt. Это – наибо- лее простое задание исполняемого файла, но любой ИК, в том числе и shell, позволяет задавать дополнительные условия выполнения запускаемой про- граммы, существенно помогающие пользователю ВС в изложении требуемой ему задачи. Рассмотрим способы указания таких условий.
Использование метасимволов. Оно позволяет пользователю существенно сократить число набираемых имен файлов. Основные метасимволы:
1) * – соответствует любой последовательности символов, в том числе и пустой, кроме последовательностей, начинающихся с символа «.»;
2) ? – соответствует любому одиночному символу;
3) [...] – соответствует любому одиночному символу из тех, что пере- числены без разделяющих символов в квадратных скобках. Пара сим- волов, разделенных символом «–», соответствует одиночному симво- лу, код которого попадает в диапазон между кодами указанных символов, включая их самих.
Для самих запускаемых программ метасимволы shell «незаметны», так как shell подставляет вместо имен, использующих их, обычные имена фай- лов. Например, пусть пользователь набрал последовательность команд (напом- ним, что утилита ls без параметров выводит на экран содержимое текущего каталога):
$ ls client client.c server.c
$ cc *.c
Тогда действительный вызов транслятора cc, выполняемый shell, име- ет вид: cc client.c server.c.


60
Перенаправление ввода-вывода. Оно позволяет пользователю в удобной форме выполнить замену файлов, используемых в качестве стандартного ввода и стандартного вывода запускаемой программы. Напомним, что по умолчанию стандартным вводом является клавиатура, а стандартным выводом – экран. По умолчанию экран используется также в качестве второго выходного файла, в который выводятся сообщения об ошибках. Перечислим операции перена- правления ввода-вывода:
1) > файл программа выполняет вывод данных не на экран, а в задан- ный файл, начиная с его начала. Если файл с таким именем уже суще- ствует, то его прежнее содержимое будет уничтожено. Если файл не существует, то он будет создан;
2) >> файл – программа добавляет свои выходные данные в конец су- ществующего файла. Если файла не было, то он создается;
3) < файл – программа выполняет ввод данных не с клавиатуры, а из заданного файла;
4) << слово – программа выполняет ввод данных с клавиатуры до тех пор, пока в этих данных не встретится заданное слово или не будет введен символ конца файла (<Ctrl>&<D>).
Подобно использованию метасимволов, сама запускаемая программа ни- чего «не знает» об используемых в команде операциях перенаправления ввода- вывода. Дело в том, что программа обращается к экрану и клавиатуре не по их пользовательским именам (именам соответствующих файлов), а использует для этого программные имена файлов: клавиатура – 0; экран – 1; экран для вывода ошибок – 2. Поэтому обработка операции перенаправления ввода-вывода в ИК заключается в том, что прежде чем будет запущена требуемая программа, ИК откроет под номерами 0, 1, 2 не клавиатуру и экран, а файлы, указанные в пользовательской команде.
В следующих примерах операции перенаправления ввода-вывода демон- стрируются на примере утилиты cat.
1. $ cat > abc.txt
В этом примере cat используется в качестве простейшего текстового ре- дактора, который позволяет вводить текст, строка за строкой, с клавиатуры в файлabc.txt, начиная с его начала. Каждая введенная строка может быть сразу же отредактирована. Ввод символов заканчивается символом конца файла
(<Ctrl>&<D>).

61 2. $ cat >> abc.txt
Отличие этого примера от предыдущего в том, что вводимые с клавиату- ры символы добавляются в конец файлаabc.txt.
3. $ cat < abc.txt
Эта команда выводит на экран содержимое файлаabc.txt. Точно такого же эффекта можно достичь и командой:$ cat abc.txt. Разница в том, что в первом случае запускаемая утилитаcat не получает никаких параметров, а во втором случае таким параметром является имя файлаabc.txt.
4. $ cat << ! > abc.txt
Ввод с клавиатуры помещается в файл abc.txtдо тех пор, пока не бу- дет введен символ «!». В этом примере и в следующем используются сразу две операции перенаправления ввода-вывода.
5. $ cat < xy.txt > abc.txt
Эта команда выполняет копирование файлаxy.txtв файлabc.txt. То есть эта команда является некоторым аналогом команды cp.
Так как системные утилиты выводят свои сообщения об ошибках на экран, то эти сообщения иногда мешают восприятию с экрана другой информа- ции и тем самым раздражают пользователя. Для подавления таких сообщений их перенаправляют с экрана в другой файл, например в файл с именем
/dev/null
. Этот файл соответствует псевдоустройству, вывод в который означает уничтожение выводимой информации. Сама операция перенаправле- ния сообщений об ошибках аналогична перенаправлению стандартного вывода с тем лишь отличием, что слева от операции «>» или «>>» записывается цифра
«2» – программное имя файла, предназначенного для вывода ошибок.
Например, следующие две команды выводят на экран содержимое всех текстовых файлов, содержащихся в текущем каталоге: а) cat./*; б) саt./* 2>/dev/null.
Программа cat, запущенная первой из этих команд, выводит на экран свое «ругательство» по поводу каждого нетекстового файла или подкаталога.
Второй запуск этой программы выводит на экран лишь содержимое текстовых файлов.
Запуск исполняемого файла в фоновом режиме. Если запускаемая про- грамма использует клавиатуру и (или) экран, то она относится к запускающему ее ИК логически так же, как относится подпрограмма к запускающей ее про-


62 грамме. То есть так как ИК не может выполняться без экрана и клавиатуры, ко- торые существуют для конкретного пользователя в единственном экземпляре, то до завершения запущенной программы ИК будет «без движения». При этом говорят, что программа запускается в оперативном режиме.
Если программе не нужны ни клавиатура, ни экран, то ее можно запу- стить в фоновом режиме. Это означает, что после запуска программы она и ИК выполняются асинхронно (независимо). (На самом деле, как будет показано в следующих разделах, ИК может выполнять некоторые действия по управле- нию запущенной программой, но эти действия не являются обязательными и зависят от желания пользователя.)
Для запуска исполняемого файла в фоновом режиме достаточно в конце команды записать символ «&». Например, следующая команда выполняет в фоновом режиме копирование поддерева файловой структуры с корнем dir1 в поддерево с корнем dir2:
$ cp -r dir1 dir2 &.
1   2   3   4   5   6   7   8   9   ...   23

2.5.3 Составные команды
В отличие от простой команды составная команда позволяет пользовате- лю запустить не один, а несколько исполняемых файлов. Такая команда пред- ставляет собой или конвейер, или командный список, или многоуровневую ко- манду.
Конвейер программ. Имена исполняемых файлов, образующих конвейер, разделяются символом «|». Стандартный вывод программы, стоящей слева от этого символа, одновременно является стандартным вводом для программы, записанной справа. Пример конвейера:
$ find dir1 -name a1 | cat > file.
В этом примере утилитаfind выводит список файлов с простым именем a1
, находящихся в поддереве файловой структуры с корнемdir1(это подка- талог текущего каталога). Причем вывод осуществляется не на экран, а в файл на диске, из которого утилитаcat переписывает имена файлов в файлfile.
Программы, образующие конвейер, не конкурируют между собой из-за экрана и клавиатуры, так как клавиатура может быть нужна только первой, а экран – только последней программе конвейера. Поэтому эти программы за- пускаются shellодновременно (асинхронно). После запуска программы, рас- положенные по соседству в конвейере, взаимодействуют между собой через

63 промежуточный файл следующим образом. Программа, для которой этот файл является выходным, помещает в него свои данные построчно (в приведенном примере каждая строка содержит имя файла). Другая программа считывает эти данные также построчно, не дожидаясь завершения работы первой программы.
Заметим, что несмотря на то, что промежуточный файл реально существует на диске, его имя неизвестно для пользователя, которому, впрочем, это имя и не нужно.
Для того чтобы сохранить промежуточный файл, скопировав его в другой файл, используется команда tee, помещаемая в то место конвейера, где нахо- дится промежуточный файл. Если сравнить конвейер с водопроводной трубой, то эта команда играет роль «тройника» (рис. 2.10). Переделаем предыдущий пример так, чтобы, по-прежнему сохраняя результаты поиска в файлеfile, обеспечить их вывод на экран:
$ find dir1 -name a1 | tee file | cat.
Рис. 2.10  Наглядное изображение команды tee
Если первой и последней командам конвейера не нужны соответственно клавиатура и экран (например, благодаря перенаправлению ввода-вывода), то все программы конвейера могут быть запущены в фоновом режиме записью символа «&» в конце конвейера.
Подобно тому, как команда запуска программы имеет код завершения, подобный код имеет и конвейер. При этом код завершения конвейера определя- ется кодом завершения программы, записанной в конвейере последней.
Командные списки. Такой список образуют конвейеры, разделенные сим- волами: «;», «&», «&&», «||». При этом в качестве конвейеров могут выступать и отдельные исполняемые файлы. Рассмотрим назначение перечисленных сим- волов:
 ; – элементы списка, соединяемые этим символом, запускаются по- следовательно. То есть программа (конвейер) справа от символа «;»

64 начинает выполняться только после завершения программы (конвейе- ра) слева. При этом программа слева выполняется в оперативном ре- жиме и поэтому может использовать экран и клавиатуру;
 & – элементы списка, соединяемые этим символом, запускаются асин- хронно. При этом программа или конвейер слева от этого символа за- пускается в фоновом режиме;
 && – элементы списка, соединяемые этим символом, запускаются по- следовательно. При этом конвейер справа будет запущен только в том случае, если конвейер слева завершился успешно – с нулевым кодом завершения;
 || – в отличие от предыдущего случая для запуска конвейера справа требуется неудачное завершение конвейера слева (завершение с нену- левым кодом завершения).
Примеры командных списков:
1) $ mkdir dir1; cd dir1; pwd
/home/vlad/dir1 2) $ cp -r dir2 dir3 & cat > file1 3) $ mkdir dir1 && cd dir1 4) $
mkdir dir1 || echo "Ошибка создания каталога dir1"
Многоуровневая команда. Такая команда представляет собой текст одной команды, в которую должны быть подставлены результаты выполнения другой команды или команд. При этом результат вкладываемой команды представляет собой одну или несколько текстовых строк, отображаемых в стандартный вы- вод. Примеры таких команд: pwd, wc, ls, find. Каждая вкладываемая команда должна быть выделена одним из двух способов: а) заключена в обратные апо- строфы «`»; б) заключена в круглые скобки, которым предшествует символ
«$». Первый из этих способов применяется, в основном, для двухуровневых команд, а второй – для любого числа уровней вложенности.
Shell обрабатывает многоуровневую команду (как и любую другую) слева направо. При этом, встретив очередную вложенную команду, shell обеспечивает ее выполнение, а затем подставляет текст, полученный в резуль- тате этого выполнения, в командную строку. Если данный текст состоит из не- скольких строк, то shell заменяет каждую пару символов «возврат каретки» и

65
«перевод строки», разделяющих соседние строки, на символ пробела. В резуль- тате этого вставляемый текст представляет собой одну большую строку.
· · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · · ·
Следующая двухуровневая команда выполняет уничтожение всех файлов и каталогов, простые имена которых начинаются с буквы d и которые располо- жены в поддереве файловой структуры, принадлежащем данному пользователю:
$ rm -r ‘find / -name ‘d*’’
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Обратите внимание, что при задании в команде find имени файла (или каталога) с помощью метасимволов, это имя обязательно должно быть заклю- чено в кавычки (одиночные или двойные). Это объясняется тем, что shell имеет свои метасимволы, одноименные метасимволам утилиты find. Кавычки играют роль «экранирующих» символов, сообщая shell о том, что все симво- лы, заключенные между ними, являются обычными символами, которые долж- ны быть переданы без изменений в запускаемую программу (в данном случае в программу find).
Полезно сравнить действие записанной двухуровневой команды с коман- дой: $ rm -r /d*. Последняя команда выполнит уничтожение не всех фай- лов и каталогов с заданным именем в поддереве пользователя, а лишь тех, для которых родительским каталогом является корень этого поддерева.
· · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · · ·
Следующая команда имеет 4-уровневую структуру:
$ echo 111$(echo 222$(echo 333$(echo 444)))
111222333444
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
2.5.4 Переменные и выражения
Как и любой язык программирования, входной язык ИК позволяет зада- вать переменные. При этом под переменной понимается небольшая область ОП, содержащая данное, которое может быть использовано при выполнении команд shell
. В отличие от других языков программирования переменные shell не

66 нуждаются в объявлении типа, так как все они содержат данные одного типа – символьные строки.
Имя переменной может включать символы: латинские буквы, цифры,
«_». При этом имя не может начинаться с цифры. Как и всегда, для задания значения переменной используется оператор присваивания. В shell это сим- вол «=». Имя присваиваемой переменной помещается слева от этого символа, а справа – новое значение переменной. Для задания этого значения могут быть использованы следующие способы.
Непосредственное задание строки символов. Если эта строка состоит из одного слова, то ее можно не выделять. Для задания строки из нескольких слов обязательны двойные кавычки.
· · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · · ·
$ var1=/home/vlad/a.txt
$ var2="/home/vlad/a.txt"
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В результате выполнения этих операторов переменныеvar1 иvar2 имеют одинаковое значение.
Задание значения другой переменной. Для этого перед именем перемен- ной в правой части оператора присваивания должен быть помещен символ «$».
· · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · · ·
$ var1=/home/vlad/a.txt
$ var2=$var1
$ echo $var2
/home/vlad/a.txt
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В этом примере значение переменнойvar1 используется для задания значения переменной var2. А значениеvar2 используется в качестве пара- метра командыecho.
Использование выходных данных команды shell. Оно выполняется точ- но так же, как и в многоуровневой команде (см. пп. 2.5.3). При этом имя любой программы, которая выдает свой результат в виде одной или нескольких строк символов, может быть записано справа от оператора присваивания, заключен-

67 ным в обратные апострофы «`», или может быть заключено в круглые скобки, которым предшествует символ «$».Shell сначала запускает указанную про- грамму на выполнение, а затем подставляет ее выходные данные в качестве значения заданной переменной.
· · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · · ·
$ var=`pwd`
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В данном примере shell сначала запустит на выполнение утилитуpwd, которая выдаст имя текущего каталога, затем подставит это имя в качестве зна- чения переменной var.
Использование команды ввода read. Оно позволяет ввести значения пе- ременных со стандартного ввода (с клавиатуры), не используя оператор при- сваивания. Для этого имена определяемых переменных должны быть перечис- лены в качестве параметров этой команды. Вводимые далее с клавиатуры (до нажатия ) слова распределяются между переменными так, что в одну переменную записывается одно слово. Если число переменных меньше числа слов в введенной строке, то все оставшиеся слова записываются в последнюю переменную. Если, наоборот, число переменных больше, то последние пере- менные получат пустое значение. Если с клавиатуры вместо обычных символов будет введен символ конца файла (>&<D>), то данная команда завершит- ся с ненулевым кодом завершения.
Команду read удобно использовать для того, чтобы присваивать пере- менным значения слов из некоторого текстового файла. Для этого достаточно перенаправить стандартный ввод с клавиатуры на ввод из требуемого файла.
Например, следующая команда присваивает переменным x, y, z значения слов из первой строки файла file:
$ read x y z < file
Таким образом, для того, чтобы определить обыкновенную переменную, достаточно хотя бы раз записать ее имя слева от оператора присваивания или записать его в качестве параметра команды read. После этого до конца вашей работы с данным shell значение данной переменной может использоваться в любом месте любой команды. Для этого имени переменной должен предше- ствовать символ «$», смысл которого в данном случае есть «значение перемен-

68 ной». Выше приведены примеры использования значения переменной в правой части оператора присваивания, а также в качестве параметра команды echo.
Если имя переменной следует отделить от символов, записанных сразу за ним, то это имя следует заключить в символы «{» и «}».
· · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · · ·
$ var=abc
$ echo $varxy
$ echo ${var}xy abcxy
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В данном примере в качестве параметра первого оператора echoзаписа- но значение неопределенной ранее переменной varxy. В подобных случаях shell подставляет вместо неопределенной переменной пустое место. Второй операторecho получает в качестве своего параметра значение переменной var
(символы abc), к которому «подсоединены» символы xy.
Используя утилиту set (без параметров), можно вывести на экран пере- чень переменных, определенных в данном сеансе работы с shell, а также их значения. В состав данных переменных входят не только обыкновенные пере- менные, заданные операторами присваивания, но и переменные окружения – переменные, которые shell «наследует» от программы, запустившей его.
(В гл. 3 будет показано, что любая обрабатывающая программа имеет «роди- тельскую программу».) Рассмотрим некоторые переменные окружения:
1) HOME – содержит полное имя корневого каталога пользователя;
2) PATH – содержит перечень абсолютных имен каталогов, в которых shell выполняет поиск исполняемого файла в том случае, если для его задания в своей команде пользователь использовал простое имя файла. Имена-пути каталогов, записанные в данной переменной, раз- деляются символом «:». Следует отметить, что shell не производит поиск исполняемого файла в текущем каталоге по умолчанию, и для этого требуется явное задание текущего каталога в переменной PATH
(для этого используются символы «./»). Кроме того, заметим, что shell не использует данную переменную для поиска неисполняе- мых, например текстовых, файлов. Поэтому для задания таких файлов

69 в команде пользователя требуется или использовать их абсолютные имена, или обеспечить перед выполнением такой команды переход в родительский каталог файла;
3) PS1 – приглашение shell в командной строке (обычно – $);
4) PS2 – вторичное приглашение shell в командной строке (обычно –
>
). Выводится на экран в том случае, когда вводимая команда пользо- вателя занимает более одной строки.
Используя оператор присваивания, можно заменить содержимое пере- менной окружения подобно тому, как это делается для обыкновенных перемен- ных. Например, следующая команда добавляет в переменную PATHимя теку- щего каталога: $ PATH=${PATH}":./".
Изменение переменной окружения приведет к тому, что не только теку- щая программа shell, но и все запущенные ею программы будут использовать новое значение данной переменной. В то же время программы, являющиеся
«предками» данного shell, по-прежнему будут работать с ее прежним значе- нием.
Обыкновенные переменные можно добавить к переменным окружения, сделав их «наследуемыми». Для этого достаточно перечислить имена этих пе- ременных в качестве параметров команды export.
Подобно другим языкам программирования, входной язык shellпозво- ляет записывать выражения.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Выражение – совокупность нескольких переменных и (или)
констант, соединенных знаками операций. Различают арифмети-
ческие и логические выражения.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Арифметические выражения имеют при программировании для shell весьма ограниченное значение. Вспомним, что данный язык даже не имеет арифметических типов данных. Если все-таки требуется выполнить над пере- менными shell арифметические действия, то для этого следует использовать команду (функцию shell) expr.
· · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · · ·
$ expr 5 + 3 8

70
$ expr 5 "*" 3 15
$ x=10
$ expr $x + 1 11
$ x=20
$ x=`expr $x + 2`
$ echo $x
22
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Заключение в кавычки знака умножения обусловлено тем, что данный символ является для shell метасимволом, и поэтому для устранения его спе- циальных свойств он должен быть «экранирован». Обратите внимание, что зна- ки арифметических операций должны быть окружены пробелами.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Логическое выражение – выражение, имеющее только два
значения – 0 (истина) и 1 (ложь).
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Операндами логического выражения являются операции отношения, каждая из которых или проверяет отношение файла (или строки символов) к заданному свойству, или сравнивает между собой два заданных числа (или две строки символов). Если проверяемое отношение выполняется, то результа- том операции отношения является 0, иначе – 1. Перечислим некоторые из опе- раций отношения:
-s file размер файла file больше 0
-r file для файла file разрешен доступ на чтение
-w file для файла file разрешен доступ на запись
-x file для файла file разрешено выполнение
-f file файл file существует и является обычным файлом
-d file файл file существует и является каталогом
-z string строка string имеет нулевую длину
-n string строка string имеет ненулевую длину string1 = string2 две строки идентичны string1 != две строки различны

71 string2 i1 -eq i2 число i1 равно числу i2 i1 -ne i2 число i1 не равно числу i2 i1 -lt i2 число i1 строго меньше числа i2 i1 -lе i2 число i1 меньше или равно числу i2
i1 -gt i2 число i1 строго больше числа i2
i1 -gе i2 число i1 больше или равно числу i2
При записи логического выражения отдельные операции отношения мо- гут соединяться друг с другом с помощью логических операций:
 ! – логическое отрицание;
 -a – логическое И;
 -o – логическое ИЛИ.
При этом наибольший приоритет имеет операция !, а наименьший –
-o
. Приоритеты операций определяют порядок их выполнения. Порядок вы- полнения логических операций можно изменить, используя круглые скобки.
Для shell характерно то, что запись логического выражения еще не означает его автоматического вычисления. Для этого требуется, чтобы элемен- ты логического выражения были записаны в качестве параметров команды test
. Результатом выполнения этой команды является код завершения: 0 – ло- гическое выражение истинно, 1 – ложно. Команду testможно задать одним из двух способов: 1) обычным способом; 2) заключив логическое выражение в квадратные скобки.
· · · · · · · · · · · · · · · · · · · · · · · · ·
Пример
· · · · · · · · · · · · · · · · · · · · · · · · ·
$ var1 = 10; var2 = 20; var3 = 30 1) $ test $var1 –gt $var2 && echo "var1 > var2"
2) $ [ $var1 –gt $var2 ] || echo "var1 <= var2" var1 <= var2 3) $ test $var1 = $var2 && echo "var1 = var2"
4) $ [ $var1 = $var2 –o $var2 != $var3 ] && echo
"===="
====
5) $ test \($var1 –eq $var2 \) && echo "var1 = var2"
6) $ [ ! \($var1 –eq 0 \) ] && echo "var1 не равно 0"

72 var1 не равно 0 7) $ test \($ var1 != $var2 \) –a \($var1 –eq $var2
\) || echo "????"
????
8) $ [ abc ] && echo true true
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
В примерах 1 и 2 операции отношения сравнивают численные значения переменных. В зависимости от этих значений выводятся соответствующие со- общения на экран. В примере 2 команда test задается с помощью квадратных скобок, которые обязательно отделяются от логического выражения пробелами.
В примерах 3 и 4 содержимое каждой переменной рассматривается не как число, а как строка символов. Обратите внимание, что операция проверки идентичности строк (=) в отличие от операции присваивания выделяется с обе- их сторон пробелами.
В примерах 5, 6 и 7 для выделения логического выражения или его частей используются круглые скобки. При записи каждой круглой скобки должны быть выполнены два требования: 1) непосредственно перед скобкой должен быть помещен символ «\»; 2) перед символом «\» и после скобки обязательно должны быть записаны пробелы. Наличие первого требования обусловлено тем, что круглые скобки рассматриваются интерпретатором shellкак слу- жебные символы. Для того, чтобы эти скобки не выполняли свои служебные функции, а были переданы без изменений в подпрограмму, выполняющую ко- манду test, они должны быть «экранированы». Такое «экранирование» и вы- полняет символ «\». Интересно отметить, что в примере 7 операции отношения
(записаны в круглых скобках) всегда дают противоположный результат. При этом в первой из них переменные сравниваются как строки символов, а во вто- рой рассматриваются их численные значения.
Пример 8 иллюстрирует тот факт, что команда testвыдает значение 0
(истина), если вместо логического выражения записано любое непустое слово.
Во всех приведенных выше примерах команда test, выполняющая вы- числение логического выражения, записывается в качестве первой команды командного списка, управляя выполнением второй команды этого списка. Дру- гим применением этой команды являются управляющие операторы shell.

73
1   2   3   4   5   6   7   8   9   10   ...   23