Операционные системы. Управление ресурсами

       

Командные файлы и язык процедур


Принцип пользователя диктует необходимость короткого обращения к часто выполняемым последовательностям команд. Простым и эффективным решением этой задачи является запись такой последовательности в текстовый файл и обращение к ней в дальнейшем по имени файла. Мы будем называть такие файлы командными файлами. В интерактивных системах их иногда также называют пакетными файлами (batch file), а в пакетных - файлами процедур JCL. Командный интерпретатор должен при вводе команды-обращения к такому файлу распознать тип файла (иногда признак обращения к командному файлу требуется указать в самой команде) и далее считывать и интерпретировать команды из файла.

В простейшем случае командный файл содержит неизменяемую последовательность команд и является просто аббревиатурой этой последовательности. Но сервис, обеспечиваемый инвариантными последовательностями, явно недостаточен. Например, для программиста типичным является "сценарий" работы, состоящий из многократного повторения таких шагов:

  • редактирование исходного модуля;
  • компиляция;
  • компоновка;
  • выполнение.

Каждый шаг связан с вызовом новой программы, следовательно, с новой командой. Очевидно, что при записи такого сценария в командный файл мы должны обеспечить для него хотя бы один параметр - имя исходного модуля. Параметры являются совершенно необходимым свойством для командных файлов. Параметры нетрудно обрабатывать простой текстовой подстановкой.

Очевидно также, что в том же сценарии не имеет смысла компоновать, а тем более выполнять программу, если при компиляции в ней обнаружены ошибки. Отсюда - необходимость управлять последовательностью выполнения команд в командном сценарии. Простейшим вариантом такого управления является включение в команду условия ее выполнения, более сложный и гибкий вариант - условный переход на ту или иную команду. В условии выполнения или перехода должен анализироваться код завершения одной или нескольких предыдущих команд. Общепринятым является успешное завершение программ и команд с кодом 0. Код завершения может формироваться программой, выполняющей команду, как параметр системного вызова exit и восприниматься процессом-родителем (командным интерпретатором) в системном вызове wait.

Параметры и условия являются тем набором средств, который обеспечивает минимальный необходимый сервис. Некоторые ОС на этом и останавливаются. Другие же идут дальше. "Пионером" в этой области (как и во многих других) является ОС Unix. Это неудивительно, так как Unix воплощает "философию дешевых процессов", а для того, чтобы скомпоновать из "дешевых" процессов сложные действия, нужны развитые средства интеграции. Просматривая публикации по ОС Unix в хронологическом порядке, можно наблюдать, как языковые средства shell наращивались новыми алгоритмическими возможностями, все более приближая его к процедурному языку программирования. В итоге shell обладает полным набором средств процедурного программирования (операций и операторов), включая манипулирование с переменными shell-программы, условный оператор, оператор множественного выбора, операторы циклов, оператор обработки исключительных ситуаций, а также возможность создания и вызова функций.

По иному пути пошла фирма IBM, в середине 80-х годов представившая в составе ОС CMS (гостевой ОС в среде ОС виртуальных машин VM/370) реструктурированный расширенный язык процедур - REXX (Restructured EXtended eXecutor language) [31]. Разработчики этого языка пошли не по пути наращивания командного языка алгоритмическими возможностями, а по пути включения в мощный алгоритмический язык (за основу был взят язык PL/1) средств выполнения команд. Подход оказался настолько продуктивным, что за прошедшее с тех пор время REXX практически не претерпел изменений и сейчас входит в базовый комплект поставки не только CMS VM/ESA, но всех ОС фирмы. Наряду со средствами процедурного программирования, "унаследованными" от PL/1 в REXX включен в качестве базовых операций языка ряд операций расширенной обработки строк и большое количество встроенных функций, также прежде всего связанных с обработкой строк, которыми компенсируется отсутствие того богатого набора утилит, который имеется в Unix. Кроме того, в REXX имеется возможности (эти возможности системно-зависимые) работы с текстовыми файлами и обмена данными через очереди или перенаправление ввода-вывода не только в файлы, но и в буферы, подобные программным каналам - pipe, но со структурой дека (очереди с двумя концами). Вообще область применения REXX шире, чем только применение его в качестве командного интерпретатора ОС. Целый ряд продуктов системного и промежуточного программного обеспечения IBM использует REXX как интерпретатор своих команд. Оператор ADDRESS задает имя программы-среды, в которую передается команда.

Оба типа развитых командных языков наряду с одинаковыми алгоритмическими возможностями обладают также еще одним принципиально важным общим свойством - они являются языками интерпретирующего типа. Командный файл REXX или sell не требует компиляции. Эта означает, что полный анализ такого файла не производится (или производится только в первом приближении), и интерпретатор выполняет его команда за командой, "не заглядывая" вперед. Переменные командного файла имеют единственный тип - "строка символов" и основные манипуляции над ними представляют собой строковые операции. При выполнении арифметики строковые данные прозрачно преобразуются в числовые, а результат операции вновь преобразуется в строку. При выполнении каждого очередного оператора командного файла производится подстановка вместо переменных shell- или REXX-программы их значений. В обоих языках предусмотрены средства "экранирования", защищающие строковые литералы от интерпретации их как переменных. Строка, полученная после выполнения подстановки, интерпретируется как оператор командного языка или - если это невозможно - как команда ОС (или другой целевой среды). В REXX имеется возможность даже сформировать символьную строку в переменной REXX-программы, а затем выполнить ее как оператор языка.

Таки образом, командные языки ОС обладают всеми возможностями языков программирования, и, в принципе, пригодны для создания не только командных процедур, но и некоторых программ обработки данных. Выполнение командных файлов в режиме интерпретации, конечно, делает такие программы менее эффективными, чем программы, написанные на языках компилирующего типа, но создает в них некоторые дополнительные возможности и вырабатывает некоторый особый стиль программирования.



Содержание раздела