На разницу между этими функциями указывают последние буквы их названий. Различия между ними собраны в табл. 27.1 и подробно описаны в следующем списке.
• Большинство функций семейства exec() ожидают получить путь к программе, которую нужно загрузить. Но execlp() и execvp() позволяют указать лишь имя файла. В этом случае файл ищется в каталогах из списка, заданного в переменной среды PATH (подробнее о ней читайте ниже). Такой же поиск выполняется командной оболочкой, когда в нее вводят название команды. Чтобы обозначить эту особенность, имена этих функций содержат букву p (от PATH). Переменная PATH игнорируется, если в имени файла присутствует слеш (/): в этом случае имя воспринимается как относительный или абсолютный путь.
• Вместо того чтобы передавать новой программе список аргументов argv в виде массива, функции execle(), execlp() и execl() используют для этого список. Первый из этих аргументов соответствует элементу argv[0] в функции main() новой программы и, следовательно, совпадает с аргументом filename или последней частью аргумента pathname. В конце списка аргументов должен находиться нулевой указатель, чтобы данные вызовы могли определить конец (в прототипах, приведенных выше, это требование обозначено закомментированным (char *) NULL). Чтобы отличить данные функции от тех, что передают список аргументов в виде массива с NULL в конце, их имена содержат букву l (от list — «список»). Функции, которые применяют для этой цели массив (execve(), execvp() и execv()), обозначены буквой v (от vector — «вектор»).
• Функции execve() и execle() позволяют программисту явно задать переменные среды для новой программы, используя аргумент envp — массив указателей на символьные строки, который заканчивается значением NULL. Чтобы обозначить этот факт, имена данных функций заканчиваются буквой e (от environment — «среда»). Остальные функции семейства exec() применяют для новой программы среду вызывающего процесса (то есть содержимое глобальной переменной environ).
В библиотеке glibc версии 2.11 появилась нестандартная функция execvpe(file, argv, envp). Она похожа на execvp(), но вместо того, чтобы наследовать переменные среды для новой программы из environ, она принимает их в виде аргумента envp (по аналогии с execve() и execle()).
На следующих нескольких страницах будут демонстрироваться примеры использования этих разновидностей вызова exec().
Таблица 27.1. Краткое перечисление различий между разными функциями вида exec()
Функция — Задание программного файла (-, p) — Задание аргументов (v, l) — Источник переменных среды (e, — )
execve() — pathname — Массив — Аргумент envp
execle() — pathname — Список — Аргумент envp
execlp() — filename + PATH — Список — environ вызывающего процесса
execvp() — filename + PATH — Массив — environ вызывающего процесса
execv() — pathname — Массив — environ вызывающего процесса
execl() — pathname — Список — environ вызывающего процесса
27.2.1. Переменная среды PATH
Функции execvp() и execlp() позволяют нам указать только имя файла, который нужно выполнить. Для его поиска они используют переменную среды PATH. Значение PATH представляет собой строку с именами каталогов
$ echo $PATH
/home/mtk/bin:/usr/local/bin:/usr/bin:/bin:.
При входе в систему значение PATH настраивается общесистемными и пользовательскими скриптами. Поскольку потомок наследует копию переменных среды своего родителя, каждый процесс, создаваемый командной оболочкой для выполнения команды, получает дубликат переменной PATH из оболочки.
Пути, заданные в PATH, могут быть либо абсолютными (если начинаются со знака /), либо относительными. Относительный путь интерпретируется с учетом текущего каталога вызывающего процесса. Текущий каталог можно задать с помощью символа. (точка), как в вышеприведенном примере.
Текущий каталог в переменной PATH можно также задать в виде префикса нулевой длины — двух двоеточий подряд или начального/завершающего двоеточия (например, /usr/bin:/bin:). В стандарте SUSv3 такой подход считается устаревшим; текущий каталог следует указывать явно с помощью символа. (точка).
Если переменная PATH не определена, функции execvp() и execlp() по умолчанию используют список путей вида.:/usr/bin:/bin.