Я пытаюсь запустить внешнее приложение через system()
- например, system("ls")
. Я хотел бы записать его вывод, поскольку это происходит, поэтому я могу отправить его на другую функцию для дальнейшей обработки. Какой лучший способ сделать это в C/С++?
Оптимизация захвата stdout из команды system()
Ответ 1
В раскрывающемся руководстве:
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
Ответ 2
Попробуйте функцию popen(). Он выполняет команду, например system(), но направляет вывод в новый файл. Возвращается указатель на поток.
FILE *lsofFile_p = popen("lsof", "r");
if (!lsofFile_p)
{
return -1;
}
char buffer[1024];
char *line_p = fgets(buffer, sizeof(buffer), lsofFile_p);
pclose(lsofFile_p);
Ответ 3
РЕДАКТИРОВАТЬ: неверный вопрос, поскольку вы хотите передать вывод в другую программу, а не другую функцию. popen() почти наверняка вы хотите.
Система предоставляет полный доступ к оболочке. Если вы хотите продолжить его использование, вы можете перенаправить его на временный файл, по системе ( "ls > tempfile.txt" ), но выбор защищенного временного файла - это боль. Или вы можете перенаправить его через другую программу: system ( "ls | otherprogram" );
Некоторые могут рекомендовать команду popen(). Это то, что вы хотите, если вы сами можете обработать результат:
FILE *output = popen("ls", "r");
который даст вам указатель FILE, с которым вы можете читать, с выходом команды на нем.
Вы также можете использовать вызов pipe() для создания соединения в сочетании с fork() для создания новых процессов dup2() для изменения стандартного ввода и вывода из них, exec() для запуска новых программ и wait() в основной программе, чтобы дождаться их. Это просто настройка трубопровода так же, как и оболочка. См. Справочную страницу pipe() для получения более подробной информации и примера.
Ответ 4
Функции popen()
и такие не перенаправляют stderr и такие; Я написал popen3()
для этой цели.
Ответ 5
Наиболее эффективным способом является использование дескриптора файла stdout
напрямую, минуя FILE
поток:
pid_t popen2(const char *command, int * infp, int * outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) == -1)
return -1;
if (pipe(p_stdout) == -1) {
close(p_stdin[0]);
close(p_stdin[1]);
return -1;
}
pid = fork();
if (pid < 0) {
close(p_stdin[0]);
close(p_stdin[1]);
close(p_stdout[0]);
close(p_stdout[1]);
return pid;
} else if (pid == 0) {
close(p_stdin[1]);
dup2(p_stdin[0], 0);
close(p_stdout[0]);
dup2(p_stdout[1], 1);
dup2(::open("/dev/null", O_WRONLY), 2);
/// Close all other descriptors for the safety sake.
for (int i = 3; i < 4096; ++i) {
::close(i);
}
setsid();
execl("/bin/sh", "sh", "-c", command, NULL);
_exit(1);
}
close(p_stdin[0]);
close(p_stdout[1]);
if (infp == NULL) {
close(p_stdin[1]);
} else {
*infp = p_stdin[1];
}
if (outfp == NULL) {
close(p_stdout[0]);
} else {
*outfp = p_stdout[0];
}
return pid;
}
Чтобы прочитать вывод из использования детьми popen2()
следующим образом:
int child_stdout = -1;
pid_t child_pid = popen2("ls", 0, &child_stdout);
if (!child_pid) {
handle_error();
}
char buff[128];
ssize_t bytes_read = read(child_stdout, buff, sizeof(buff));
Как для записи, так и для чтения:
int child_stdin = -1;
int child_stdout = -1;
pid_t child_pid = popen2("grep 123", &child_stdin, &child_stdout);
if (!child_pid) {
handle_error();
}
const char text = "1\n2\n123\n3";
ssize_t bytes_written = write(child_stdin, text, sizeof(text) - 1);
char buff[128];
ssize_t bytes_read = read(child_stdout, buff, sizeof(buff));
Ответ 6
В Windows вместо использования system() используйте CreateProcess, перенаправьте вывод на канал и подключитесь к нему.
Я предполагаю, что это возможно и в некоторых вариантах POSIX?
Ответ 7
Функции popen()
и pclose()
могут быть тем, что вы ищете.
Посмотрите на руководство glibc для примера.
Ответ 8
Собственно, я только что проверил и:
-
popen проблематичен, потому что процесс разветвляется. Поэтому, если вам нужно дождаться выполнения команды оболочки, тогда вам будет не хватать ее. В моем случае моя программа была закрыта еще до того, как труба приступила к работе.
-
В итоге я использовал системный вызов с командой tar в linux. Возвращаемое значение из системы было результатом tar.
Итак: , если вам нужно вернуть значение, тогда не только нет необходимости использовать popen, он, вероятно, не будет делать то, что вы хотите.
Ответ 9
На этой странице: capture_the_output_of_a_child_process_in_c описывает ограничения использования popen vs. using fork/exec/dup2/STDOUT_FILENO.
У меня возникают проблемы вывод tshark с помощью popen.
И я предполагаю, что это ограничение может быть моей проблемой:
Он возвращает поток stdio, а не файловый дескриптор, который не подходит для обработки вывода асинхронно.
Я вернусь к этому ответу, если у меня есть решение с другим подходом.
Ответ 10
Я не совсем уверен, что это возможно в стандартном C, поскольку два разных процесса обычно не разделяют пространство памяти. Самый простой способ, которым я могу это сделать, это заставить вторую программу перенаправить свой вывод в текстовый файл (programname > textfile.txt), а затем прочитать этот текстовый файл для обработки. Однако это может быть не лучшим образом.