Команды и командный интерпретатор


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

Командная строка состоит из имени команды (то есть имени выполняемого фай­ла), за которым следует список аргументов, разделённых пробелами. Оболочка разбивает командную строку на компоненты. Указанный в команде файл загружается, и ему обеспечивается доступ к заданным в команде аргументам.

Любой командный язык семейства shell фактически состоит из трёх частей:

¨ служебных конструкций, позволяющих манипулировать с текстовыми строками и строить сложные команды на основе простых команд;

¨ встроенных команд, выполняемых непосредственно интерпретатором команд­ного языка;

¨ команд, представляемых отдельными выполняемыми файлами.

В свою очередь, набор команд последнего вида включает стандартные команды (системные утилиты, такие как vi, cc и т. д.) и команды, созданные пользователями системы. Для того чтобы выполняемый файл, разработанный пользовате­лем ОС UNIX, можно было запускать как команду shell, достаточно определить в одном из исходных файлов функцию с именем main (имя main должно быть глобальным, то есть перед ним не должно указываться ключевое слово static). Если употребить в качестве имени команды имя такого выполняемого файла, команд­ный интерпретатор создаст новый процесс и запустит в нём указанную выпол­няемую программу, начиная с вызова функции main.

Тело функции main, вообще говоря, может быть произвольным (для интерпрета­тора существенно только наличие входной точки в программу с именем main), но для того, чтобы создать команду, которой можно задавать параметры, нужно придерживаться некоторых стандартных правил. В этом случае каждая функция main должна определяться с двумя параметрами – argc и argv. После вызова ко­манды параметру argc будет соответствовать число символьных строк, указан­ных в качестве аргументов вызова команды, а argv – массив указателей на пе­ременные, содержащие эти строки. При этом имя самой команды составляет первую строку аргументов (то есть после вызова значение argc всегда больше или равно 1). Код функции main должен проанализировать допустимость задан­ного значения argc и соответствующим образом обработать заданные текстовые строки.

Например, следующий текст на языке С может быть использован для создания команды, которая выводит на экран текстовую строку, заданную в качестве её аргумента:

#include <stdio.h>

main(argc, argv)

{

int argc;

char* argv[ ];

if(argc!=2)

{

printf(“usage: %s your-text\n”, argv[0]);

exit;

}

printf(“%s\n”, argv[1]);

}

Процессы

Процесс в ОС UNIX понимается в классическом смысле этого термина, то есть как программа, выполняемая в собственном виртуальном адресном пространст­ве. Когда пользователь входит в систему, автоматически создается процесс, в ко­тором выполняется программа командного интерпретатора. Если командному интерпретатору встречается команда, соответствующая выполняемому файлу, то он создает новый процесс и запускает в нём соответствующую программу, начи­ная с функции main. Эта запущенная программа, в свою очередь, может создать процесс и запустить в нём другую программу (она тоже должна содержать функ­цию main) и т. д.

Для образования нового процесса и запуска в нём программы используются два системных вызова API – fork( ) и ехес(имя_выполняемого_файла). Системный вызов fork приводит к созданию нового адресного пространства, состояние которого абсолютно идентично состоянию адресного пространства основного процесса (то есть в нём содержатся те же программы и данные). Для дочернего процесса заво­дятся копии всех сегментов данных.

Другими словами, сразу после выполнения системного вызова fork основной (родительский) и порожденный процессы являются абсолютными близнецами;

управление и в том и в другом находится в точке, непосредственно следующей за вызовом fork. Чтобы программа могла разобраться, в каком процессе она те­перь работает – в основном или порождённом, функция fork возвращает разные значения: 0 в порождённом процессе и целое положительное число (идентифи­катор порождённого процесса – так называемый PID) в основном процессе.

Теперь, если мы хотим запустить новую программу в порождённом процессе, нужно обратиться к системному вызову ехес, указав в качестве аргументов вызо­ва имя файла, содержащего новую выполняемую программу, и, возможно, одну или несколько текстовых строк, которые будут переданы в качестве аргументов функции main новой программы. Выполнение системного вызова ехес приводит к тому, что в адресное пространство порожденного процесса загружается но­вая выполняемая программа и запускается с адреса, соответствующего входу в функцию main. Другими словами, это приводит к замене текущего программно­го сегмента и текущего сегмента данных, которые были унаследованы при вы­полнении вызова fork, на новые соответствующие сегменты, заданные в файле. Прежние сегменты теряются. Это эффективный метод смены выполняемой про­цессом программы, но не самого процесса. Файлы, уже открытые до выполнения примитива ехес, остаются открытыми после его выполнения.

В следующем примере пользовательская программа, вызываемая как команда shell, выполняет в отдельном процессе стандартную команду shell ls, которая выдаёт на экран содержимое текущего каталога файлов.

main( )

{

if (fork ( )==(0) wait(0); /* родительский процесс */

else execl('ls", "Is", 0); /* порождённый процесс */

}

Таким образом, с практической точки зрения процесс в UNIX является объектом, создаваемым в результате выполнения функции fork( ). Каждый процесс, за исключением начального (нулевого), порождается в результате запуска дру­гим процессом операции fork( ). Каждый процесс имеет одного родителя, но мо­жет породить много процессов. Начальный (нулевой) процесс является особенным процессом, который создается в результате загрузки системы. После порожде­ния нового процесса с идентификатором 1 нулевой процесс становится процес­сом подкачки и реализует механизм виртуальной памяти. Процесс с идентифика­тором 1, известный под именем init, является предком любого другого процесса в системе и связан с каждым процессом особым образом.



Дата добавления: 2022-02-05; просмотров: 272;


Поиск по сайту:

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.009 сек.