Как я могу запустить внешнюю программу из C и проанализировать ее вывод? - PullRequest
57 голосов
/ 04 сентября 2008

У меня есть утилита, которая выводит список файлов, необходимых для игры. Как я могу запустить эту утилиту в программе на C и получить ее вывод, чтобы я мог работать с ней в рамках той же программы?

ОБНОВЛЕНИЕ: Хороший сигнал об отсутствии информации. Утилита выдает серию строк, и она должна быть полностью переносимой на Mac / Windows / Linux. Обратите внимание, я ищу программный способ запуска утилиты и сохранения ее вывода (который идет в стандартный вывод).

Ответы [ 8 ]

50 голосов
/ 04 сентября 2008

Для простых задач в среде Unix-ish попробуйте popen().

Со страницы руководства:

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

Если вы используете режим чтения, это именно то, что вы просили. Я не знаю, реализовано ли это в Windows.

Для более сложных проблем вы хотите посмотреть межпроцессное взаимодействие.

49 голосов
/ 10 марта 2015

Как уже отмечали другие, popen() - самый стандартный способ. И так как ни один ответ не предоставил пример использования этого метода, вот оно:

#include <stdio.h>

#define BUFSIZE 128

int parse_output(void) {
    char *cmd = "ls -l";    

    char buf[BUFSIZE];
    FILE *fp;

    if ((fp = popen(cmd, "r")) == NULL) {
        printf("Error opening pipe!\n");
        return -1;
    }

    while (fgets(buf, BUFSIZE, fp) != NULL) {
        // Do whatever you want here...
        printf("OUTPUT: %s", buf);
    }

    if(pclose(fp))  {
        printf("Command not found or exited with error status\n");
        return -1;
    }

    return 0;
}
9 голосов
/ 10 сентября 2008

popen поддерживается в Windows, см. Здесь:

http://msdn.microsoft.com/en-us/library/96ayss4b.aspx

Если вы хотите, чтобы он был кроссплатформенным, поп-ин это путь.

7 голосов
/ 04 сентября 2008

Итак, если вы находитесь в командной строке в среде Windows, вы можете использовать каналы или перенаправления командной строки. Например,

commandThatOutputs.exe > someFileToStoreResults.txt

или

commandThatOutputs.exe | yourProgramToProcessInput.exe

В вашей программе вы можете использовать стандартные функции ввода C для считывания вывода других программ (scanf и т. Д.): http://irc.essex.ac.uk/www.iota-six.co.uk/c/c1_standard_input_and_output.asp. Вы также можете использовать пример файла и использовать fscanf. Это также должно работать в Unix / Linux.

Это очень общий вопрос, вы можете включить больше подробностей, например, какой это тип вывода (просто текст или двоичный файл?) И как вы хотите его обработать.

Редактировать: Ура, уточнение!

Перенаправление STDOUT выглядит проблематично, мне приходилось делать это в .NET, и это доставляло мне всяческие головные боли. Похоже, правильный способ C - порождать дочерний процесс, получать указатель на файл, и внезапно у меня болит голова.

Так вот хак, который использует временные файлы. Все просто, но должно работать. Это будет хорошо работать, если скорость не является проблемой (удар по диску медленный), или если он выбрасывается. Если вы создаете корпоративную программу, лучше всего перенаправить STDOUT, используя то, что рекомендовали другие люди.

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
    FILE * fptr;                    // file holder
    char c;                         // char buffer


    system("dir >> temp.txt");      // call dir and put it's contents in a temp using redirects.
    fptr = fopen("temp.txt", "r");  // open said file for reading.
                                    // oh, and check for fptr being NULL.
    while(1){
        c = fgetc(fptr);
        if(c!= EOF)
            printf("%c", c);        // do what you need to.
        else
            break;                  // exit when you hit the end of the file.
    }
    fclose(fptr);                   // don't call this is fptr is NULL.  
    remove("temp.txt");             // clean up

    getchar();                      // stop so I can see if it worked.
}

Обязательно проверьте права доступа к файлу: сейчас он просто выбросит файл в тот же каталог, что и исполняемый файл. Возможно, вы захотите использовать /tmp в nix, C:\Users\username\Local Settings\Temp в Vista или C:\Documents and Settings\username\Local Settings\Temp in 2K/XP. Я думаю, что /tmp будет работать в OSX, но я никогда не использовал его.

3 голосов
/ 04 сентября 2008

В Linux и OS X popen() действительно является лучшим выбором, как указал dmckee, поскольку обе ОС поддерживают этот вызов. В Windows это должно помочь: http://msdn.microsoft.com/en-us/library/ms682499.aspx

2 голосов
/ 13 мая 2010

MSDN документация говорит При использовании в программе Windows функция _popen возвращает недопустимый указатель файла, из-за которого программа перестает отвечать на запросы неопределенно долго. _popen работает правильно в консольном приложении. Чтобы создать приложение Windows, которое перенаправляет ввод и вывод, см. Создание дочернего процесса с перенаправленным вводом и выводом в Windows SDK.

1 голос
/ 11 ноября 2013

Вы можете использовать system() как в:

system("ls song > song.txt");

, где ls - это имя команды для отображения содержимого папки песни, а song - папка в текущем каталоге. Результирующий файл song.txt будет создан в текущем каталоге.

0 голосов
/ 15 июля 2013
//execute external process and read exactly binary or text output
//can read image from Zip file for example
string run(const char* cmd){
    FILE* pipe = popen(cmd, "r");
    if (!pipe) return "ERROR";
    char buffer[262144];
    string data;
    string result;
    int dist=0;
    int size;
    //TIME_START
    while(!feof(pipe)) {
        size=(int)fread(buffer,1,262144, pipe); //cout<<buffer<<" size="<<size<<endl;
        data.resize(data.size()+size);
        memcpy(&data[dist],buffer,size);
        dist+=size;
    }
    //TIME_PRINT_
    pclose(pipe);
    return data;
}
...