Получить вывод команды в трубе, C для Linux

Мне нужно запустить команду CLI Linux и получить вывод stdout от C.

Я могу использовать pipe() для создания канала, затем fork/exec, перенаправить дескриптор stdout дочернего элемента в канал перед вызовом exec() и выполнить чтение из канала в parent. Плюс мне нужно подождать с ребенком.

Существует ли простой вызов для выполнения fork + redirect + exec + wait, как system() делает fork + exec + wait, только system() не выполняет перенаправление.

Есть popen(), которая выполняет fork + redirect + exec, но не ждет, поэтому я не могу получить статус выхода.

4 ответа

Решение

Это оно?

НАЗВАНИЕ
       popen, pclose - процесс ввода / вывода

СИНТАКСИС
       #include   

       FILE * popen (команда const char *, тип const char *);

       int pclose (FILE * stream);

ОПИСАНИЕ
       Функция popen() открывает процесс путем создания канала, разветвления, 
и вызывая оболочку. Поскольку труба по определению является однонаправленной, 
аргумент типа может указывать только чтение или запись, но не оба; результирующий 
Поток соответственно только для чтения или только для записи.

       Аргумент команды является указателем на строку с нулевым символом в конце 
содержащий командную строку оболочки. Эта команда передается в /bin/sh 
используя флаг -c; интерпретация, если таковая имеется, выполняется оболочкой.  
Аргумент типа - это указатель на строку с нулевым символом в конце, которая должна быть 
либо "r" для чтения или "w" для записи.

       Возвращаемое значение из popen() - нормальный стандартный поток ввода-вывода в 
во всех отношениях, за исключением того, что он должен быть закрыт с помощью pclose (), а не fclose ().  
Запись в такой поток записывает на стандартный ввод команды;  
стандартный вывод команды такой же, как и у процесса, который вызвал 
popen(), если это не изменено самой командой. Наоборот, чтение 
из потока 'popened' читает стандартный вывод команды, а 
стандартный ввод команды такой же, как и у процесса, который вызвал 
POPEN ().

       Обратите внимание, что выходные потоки popen() по умолчанию полностью буферизуются.

       Функция pclose () ожидает завершения связанного процесса 
и возвращает состояние завершения команды, возвращенное функцией wait4().

У GLib есть хорошая функция для этого - g_spawn_sync(): http://library.gnome.org/devel/glib/stable/glib-Spawning-Processes.html

Например, чтобы запустить команду и получить ее статус выхода и вывод:

const char *argv[] = { "your_command", NULL };
char *output = NULL; // will contain command output
GError *error = NULL;
int exit_status = 0;
if (!g_spawn_sync(NULL, argv, NULL, 0, NULL, NULL, 
                  &output, NULL, &exit_status, &error))
{
  // handle error here
}

Вот что я использую:

   /* simply invoke a app, pipe output*/
    pipe = popen(buf, "r" );
    if (pipe == NULL ) {
        printf("invoking %s failed: %s\n", buf, strerror(errno));
        return 1;
    }

    waitfor(10);

    while(!feof(pipe) ) {
        if( fgets( buf, 128, pipe ) != NULL ) {
            printf("%s\n", buf );
        }
    }

    /* Close pipe */
    rc = pclose(pipe);

Использование popen() а также pclose(),


popen() конечно, на самом деле не ждет, но чтение по каналу будет блокировать, пока не появятся данные.

pclose() ждет, но преждевременный вызов может отрезать некоторый вывод от разветвленного процесса. Вы хотите определить из потока, когда ребенок закончил...


Возможно, уже обсуждалось в Как я могу запустить внешнюю программу из C и проанализировать ее вывод?

Другие вопросы по тегам