Интерпретатор команд shell
Организация интерфейса с пользователем обычно не пользуется особым вниманием в курсах ОС. Причина этого в том, что вопросы интерфейса достаточно далеки от круга проблем, касающихся других основных подсистем ОС.
Однако при изучении UNIX нельзя обойти стороной такую интересную и развитую часть системы, как интерпретатор команд, чаще называемый просто шелл (shell).
Шелл не является частью ядра UNIX, по своему статусу это обычная прикладная программа, выделяющаяся только своим назначением, которое заключается в выполнении команд пользователя, задаваемых либо в интерактивном (диалоговом) режиме, либо в виде командных файлов, называемых также шелл-скриптами. Существуют различные варианты шелла, которые, совпадая в основном, предлагают несколько разные дополнительные возможности.
Набор возможностей, предоставляемых любым интерпретатором команд UNIX, настолько широк, что может быть предметом изучения в отдельном курсе. Здесь будет дано только минимальное представление о принципах работы шелла. Более подходящей формой изучения шелла являются лабораторные работы.
Шелл можно рассматривать как своеобразный язык программирования, позволяющий создавать новые программы с достаточно сложными функциями, используя в качестве основных операций вызовы других, более простых программ. При этом конструкции языка шелла имеют прямую связь с описанными выше средствами управления процессами UNIX.
Базовой конструкцией языка команд UNIX (языка shell) является простая команда. Она состоит из имени команды и, возможно, параметров, разделенных пробелами. Имя команды — это обычно имя исполняемого файла (либо двоичной программы, либо шелл-скрипта).
Большинство команд UNIX выводят результат своей работы в текстовом виде на стандартный вывод. Как и в MS-DOS, это фактически означает вывод в файл или устройство, чей хэндл равен 1. По умолчанию это означает, что результаты выводятся на управляющий терминал пользователя. Однако стандартный вывод легко может быть перенаправлен в файл или на устройство. Для этого в команде используются символы ‘>’ и ‘>>’.
Многие команды используют также стандартный ввод (хэндл 0), который по умолчанию означает данные, вводимые с клавиатуры терминала. Признаком конца ввода служит комбинация Ctrl+D. Стандартный ввод также может быть перенаправлен для чтения данных из файла или с устройства (с помощью символа ‘<’), или даже непосредственно из текста команды.
Как правило, стандартный вывод команд UNIX имеет как можно более регулярную структуру. Например, команда просмотра каталога ls -l выдает в каждой строке информацию об одном файле, без общего заголовка и без итоговых данных. Очень часто вывод команды выглядит как таблица, столбцы которой разделены знаками табуляции. Это облегчает последующую обработку выведенных данных следующими командами. Из тех же соображений команды не выдают лишних сообщений типа «Команда успешно выполнена», хотя могут выдавать сообщения об ошибках.
Для выполнения команды шелл запускает отдельный процесс. В результате выполнения команды вырабатывается код завершения процесса, который может затем быть проанализирован. Нулевое значение кода обычно означает нормальное завершение, значение, большее нуля — ошибку.
Составная команда состоит из простых команд, соединенных в виде конвейера или списка.
Конвейер означает параллельное выполнение нескольких команд с передачей данных по мере их обработки от одной команды к следующей, как на заводском конвейере. Запись конвейера состоит из нескольких команд, разделенных знаками ‘|’. Для выполнения конвейера шелл запускает одновременно работающие процессы для каждой команды, при этом стандартный вывод каждой команды перенаправляется на стандартный ввод следующей.
Список означает последовательное выполнение команд. Он состоит из нескольких команд, разделенных знаками ‘;’, ‘&&’ или ‘||’. Если две команды разделены знаком ‘;’, то следующая команда запускается после завершения предыдущей. Если команды разделены знаком ‘&&’, то следующая будет выполняться только в том случае, если код завершения предыдущей равен 0 (нормальное завершение). Напротив, знак ‘||’ означает, что следующая команда будет выполняться только в том случае, если код завершения предыдущей не равен 0 (завершение с ошибкой).
Если запись команды заканчивается символом ‘&’, то шелл запускает процесс ее выполнения в фоновом режиме, т.е. не дожидается завершения процесса, а переходит к следующей команде. При этом фоновый процесс продолжает работать параллельно с шеллом и запускаемыми им другими командами. Фоновый процесс не имеет доступа к терминалу.
Как при интерактивной работе, так и при выполнении скриптов могут определяться и использоваться переменные, имеющие строковые значения. Ряд переменных определяется системой, например, PATH содержит список каталогов, в которых шелл ищет команды, а HOME — «домашний» каталог текущего пользователя. Для получения значения переменной перед ее именем записывается символ ‘$’. В скриптах можно также использовать значения параметров, с которыми был вызван скрипт, от $1 до $9.
Шелл, как и любой язык программирования, содержит набор операторов управления порядком выполнения команд, таких как if, case, while, until, for, break и некоторые другие. Логические выражения, используемые в операторах управления, строятся на основе кодов завершения команд, при этом специальная команда test позволяет проверить разнообразные условия, такие, как существование и тип указанного файла, равенство или неравенство строковых и числовых выражений и т.п.
Скорость выполнения шелл-скриптов во много раз меньше, чем скорость компилированной программы на C или на другом языке, однако шелл позволяет резко упростить решение многих практических задач, связанных с управлением операционной системой, обработкой текстовых файлов и т.п. Это достигается за счет того, что шелл-скрипты позволяют использовать «крупные блоки»: составлять новые программы путем изощренного комбинирования уже имеющихся программ-утилит, набор которых в любой современной версии UNIX весьма обширен.
39. Виртуальные и физические адреса. Распределение памяти без использования виртуальных адресов.