Я пытаюсь запустить внешнее приложение через 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), а затем прочитать этот текстовый файл для обработки. Однако это может быть не лучшим образом.