Рассмотрим различные варианты функций exec() и spawn(). В таблице, представленной ниже, вы увидите, что некоторые функции из них предусмотрены POSIX, а некоторые — нет. Конечно, для максимальной переносимости, следует использовать только POSIX-совместимые функции.

При том, что названия функций могут показаться малопонятными, в их суффиксах есть логика.

Суффикс: Смысл: l (нижний регистр «L») Список аргументов определяется через список параметров, заданный непосредственно в самом вызове и завершаемый нулевым аргументом NULL. е Указывается окружение. p Если не указано полное имя пути программы, для ее поиска используется переменная окружения PATH. v Список аргументов определяется через указатель на вектор (массив) аргументов.

Список аргументов здесь — список аргументов командной строки, передаваемых программе.

Заметьте, что в библиотеке языка Си функции spawnlp(), spawnvp() и spawnlpe() все вызывают функцию spawnvpe(), которая, в свою очередь, вызывает POSIX-функцию spawnp(). Функции spawnle(), spawnv() и spawnl() все в конечном счете вызывают функцию spawnve(), которая затем вызывает POSIX-функцию spawn(). И, наконец, POSIX-функция spawnp() вызывает POSIX-функцию spawn(). Таким образом, в основе всех возможностей семейства spawn() лежит сам вызов spawn().

Рассмотрим теперь различные варианты функций spawn() и exec() более подробно так, чтобы вы смогли получить навык свободного использования различных суффиксов. Затем мы перейдем непосредственно к рассмотрению вызова функции spawn().

Суффикс «l»

Например, если я хочу вызвать команду ls с аргументами -t, -r, и -l (означает — «сортировать выходные данные по времени в обратном порядке и показывать выходные данные в длинном формате»), я мог бы определить это в программе так:

/* Вызвать ls и продолжить выполнение */

spawnl(P_WAIT, "/bin/ls", "/bin/ls", "-t", "-r", "-l",

 NULL);


/* Заменить себя на ls */

execl(P_WAIT, "/bin/ls", "/bin/ls", "-t", "-r", "-l",

 NULL);

Или, вариант с применением суффикса v:

char *argv[] = {

 "/bin/ls",

 "-t",

 "-r",

 "-l",

 NULL

};


/* Вызвать ls и продолжить выполнение */

spawnv(P_WAIT, "/bin/ls", argv);


/* Заменить себя на ls */

execv(P_WAIT, "/bin/ls", "/bin/ls", argv);

Почему именно такой выбор? Он дан для удобства восприятия. У вас может быть синтаксический анализатор, уже встроенный в вашу программу, и может быть удобно сразу оперировать массивами строк. В этом случае я бы рекомендовал применять варианты с суффиксом «v». Или вам может понадобиться запрограммировать вызов программы, когда вам известно, где он находится и какие имеет параметры. В этом случае, зачем вам утруждать себя созданием массива строк, когда вы знаете точно, какие нужны аргументы? Просто передайте их варианту функции с суффиксом «l».

Отметим, что мы передаем реальное имя пути программы (/bin/ls), а затем имя программы еще раз в качестве первого аргумента. Это делается для поддержки программ, которые ведут себя по-разному в зависимости от того, под каким именем они были вызваны.

Например, GNU-утилиты компрессии и декомпрессии (gzip и gunzip) фактически привязаны к одному и тому же исполняемому модулю. Когда исполняемый модуль стартует, он анализирует аргумент argv[0] (передаваемый функции main()) и принимает решение, следует ли выполнять компрессию или декомпрессию.

Суффикс «е»

Варианты с суффиксом «е» передают программе окружение. Окружение — это только своего рода «контекст», в котором работает программа. Например, у вас может быть программа проверки орфографии, у которой есть эталонный словарь. Вместо описания каждый раз в командной строке местоположения словаря вы могли бы сделать это в окружении:

$ export DICTIONARY=/home/rk/.dict

$ spellcheck document.1

Команда export предписывает командному интерпретатору создать новую переменную окружения (в нашем случае DICTIONARY) и присвоить ей значение (/home/rk/.dict).

Если вы когда-либо хотели бы использовать различные словари, вы были бы должны изменить среду до выполнения программы. Это просто сделать из оболочки:

$ export DICTIONARY=/home/rk1.altdict

$ spellcheck document.1

Но как сделать это из ваших собственных программ? Для того чтобы применять «e»-версии функций spawn() и exec(), вам следует определить массив строк, представляющих собой окружение:

char *env[] = {

 "DICTIONARY=/home/rk/.altdict",

 NULL

};


// Запуск проверки в отдельном процессе:

spawnle(P_WAIT, "/usr/bin/spellcheck",

 "/usr/bin/spellcheck", "documents.1", NULL, env);


// Запуск проверки вместо себя:

execle("/usr/bin/spellcheck", "/usr/bin/spellcheck",

 "document.1", NULL, env);

Суффикс «p»

Версии с суффиксом «p» будут искать исполняемый модуль программы в списке каталогов, приведенном в переменной окружения PATH. Вы, вероятно, отметили, что во всех примерах местоположение исполняемых модулей строго определено — /bin/ls и /usr/bin/spellcheck. А как быть с другими исполняемыми модулями? Если вы не хотите сразу определить точный путь к нужной программе, было бы лучше сделать так, чтобы места поиска исполняемых модулей вашей программе сообщил пользователь. Стандартная системная переменная PATH для этого и предназначена. Ниже приведено ее значение для минимальной системы:

PATH=/proc/boot:/bin