Короткий ответ здесь - использовать system()
или popen()
вместо execl()
. Поскольку Джейсон уже опубликовал хороший ответ об использовании popen()
, я пропущу это и объясню, как использовать execl()
на тот случай, если вам действительно все равно. Скорее всего, это все ненужный технический тупик - но, черт возьми, я уже набрал большую часть этого текста как длинную прелюдию, прежде чем обсуждать popen()
, и сейчас я не буду его выбрасывать!
Во-первых ...
При вызове execl()
все аргументы командной строки необходимо передавать отдельно. Кроме того, первый аргумент должен быть повторен как argv[0]
в любой программе main()
традиционно является названием программы. Таким образом, фиксированный вызов должен выглядеть так:
execl("/usr/bin/php", "/usr/bin/php", "-q",
"/var/www/html/phpinfo.php", (char *) NULL);
(Я добавил приведение к (char *)
, чтобы гарантировать, что нулевой указатель передается в качестве конечного аргумента, а не целое число 0, если NULL
определено как 0
, а не (void *) 0
, что законны.)
Однако ...
Это правильно воспринимает вызов execl()
, но есть большая проблема. Семейство функций exec
почти всегда используется в сочетании с fork()
и некоторым сложным pipe()
жонглированием. Это связано с тем, что функции exec
не запускают программу в отдельном процессе; они фактически заменяют текущий процесс! Поэтому, как только вы позвоните execl()
, ваш код готов. Законченный. execl()
никогда не возвращается. Если вы просто назовете это так, как сделали, вы никогда не увидите, что произойдет, поскольку ваша программа волшебным образом превратится в /usr/bin/php
процесс.
ОК, так что это за fork()
и pipe()
? На высоком уровне вам нужно разделить ваш процесс на два процесса. Родительский процесс останется «вашим» процессом, в то время как дочерний процесс немедленно вызовет execl()
и преобразуется в /usr/bin/php
. Тогда, если вы правильно соединили родительский и дочерний процессы, они смогут общаться друг с другом.
Короче говоря, если вы все еще здесь и не заснули, вам следует обратиться к мудрому оракулу в Google за более подробной информацией обо всем этом. Существует множество веб-сайтов, дающих еще (!) Подробную информацию о том, как танцевать fork
/ exec
.
Я не оставлю тебя в покое. Вот функция, которую я использую для своих собственных программ, которая делает именно то, что я обрисовал в общих чертах. На самом деле он очень похож на popen()
, с той лишь разницей, что вызывающий абонент может получить доступ к потоку stderr
ребенка в дополнение к stdin
и stdout
.
код ...
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
pid_t execute(const char *command, FILE **in, FILE **out, FILE **err)
{
pid_t pid;
int fd[6];
pipe(&fd[0]);
pipe(&fd[2]);
pipe(&fd[4]);
switch (pid = fork()) {
case -1:
perror("unable to fork()");
exit(1);
case 0:
close(fd[1]); // Close write end of stdin.
close(fd[2]); // Close read end of stdout.
close(fd[4]); // Close read end of stderr.
dup2(fd[0], STDIN_FILENO); // Have stdin read from the first pipe.
dup2(fd[3], STDOUT_FILENO); // Have stdout write to the second pipe.
dup2(fd[5], STDERR_FILENO); // Have stderr write to the third pipe.
execlp("/bin/sh", "/bin/sh", "-c", command, (char *) NULL);
perror("execlp() failed");
_exit(1);
default:
close(fd[0]); // Close read end of stdin.
close(fd[3]); // Close write end of stdout.
close(fd[5]); // Close write end of stderr.
if (in) *in = fdopen(fd[1], "wb"); else close(fd[1]);
if (out) *out = fdopen(fd[2], "rb"); else close(fd[2]);
if (err) *err = fdopen(fd[4], "rb"); else close(fd[4]);
return pid;
}
}