【问题标题】:How can I run an external program from C and parse its output?如何从 C 运行外部程序并解析其输出?
【发布时间】:2010-09-07 18:31:39
【问题描述】:

我有一个实用程序,可以输出游戏所需的文件列表。如何在 C 程序中运行该实用程序并获取其输出,以便在同一程序中对其进行操作?

更新:关于缺乏信息的好电话。该实用程序会输出一系列字符串,这应该可以跨 Mac/Windows/Linux 移植。请注意,我正在寻找一种编程方式来执行该实用程序并保留其输出(输出到标准输出)。

【问题讨论】:

标签: c external-process


【解决方案1】:

正如其他人指出的那样,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;
}

样本输出:

OUTPUT: total 16
OUTPUT: -rwxr-xr-x 1 14077 14077 8832 Oct 19 04:32 a.out
OUTPUT: -rw-r--r-- 1 14077 14077 1549 Oct 19 04:32 main.c

【讨论】:

  • 不应该if(pclose(fp))if(pclose(fp) == -1)
  • @CoolGuy:取决于你想要什么。 pclose() 返回 -1 如果获取命令的退出状态时出错,否则返回退出状态本身。由于命令传统上设置退出状态0 以指示成功,通过检查if(pclose(fp)),我们正在测试pclose() 或命令中的错误。
  • 非常感谢这个例子,它将另一个程序的输出通过管道传输到当前程序的输出。谢谢!
  • @GabrielStaples:fgets() 更适合读取文本输出而不是二进制文件,因为它一次自动获取一行,并在换行符处拆分。两者都需要while 循环,因为您无法确定整个输出是否适合BUFSIZE
【解决方案2】:

对于 Unix-ish 环境中的简单问题,请尝试 popen()

来自手册页:

popen() 函数通过创建管道、分叉和​​调用 shell 来打开一个进程。

如果您使用阅读模式,这正是您所要求的。不知道是不是在windows中实现的。

对于更复杂的问题你想查找进程间通信。

【讨论】:

  • 一些如何正确使用popen()的例子会很好。
  • 我为该函数添加了一个指向 Open Group 手册页的链接,其中包含一个示例。基本上popen 给你一个文件指针,非常像fopen。只是它允许您写入标准输入或从程序的标准输出读取,而不是与磁盘文件交互。这就是 unix 的“一切都是文件” 的工作理念。一些实现通过允许双向通信来扩展标准。
  • Thi s answer 表示 popen 在 Windows 上可用。
  • 对于使用原始文件句柄的解决方案(例如,如果您需要异步 I/O),请参阅stackoverflow.com/questions/9405985/…
【解决方案3】:

popen 在 Windows 上受支持,请参见此处:

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

如果你希望它是跨平台的,popen 是最好的选择。

【讨论】:

    【解决方案4】:

    好吧,假设您在 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 方法是生成一个子进程,获取一个文件指针,突然间我的头疼了。

    所以这里有一个使用临时文件的 hack。这很简单,但它应该工作。如果速度不是问题(撞击磁盘很慢),或者它被丢弃,这将很有效。如果您正在构建企业程序,最好使用其他人推荐的方法来研究 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.
    }
    

    确保检查您的文件权限:现在这只会将文件与 exe 放在同一目录中。您可能想考虑在 nix 中使用 /tmp,或在 Vista 中使用 C:\Users\username\Local Settings\Temp,或 C:\Documents and Settings\username\Local Settings\Temp in 2K/XP。我认为/tmp 可以在 OSX 中使用,但我从未使用过。

    【讨论】:

    • c 应该是 int,因为 fgetc 返回的是 int,而不是 char
    【解决方案5】:

    在 Linux 和 OS X 中,popen() 确实是您最好的选择,正如 dmckee 指出的那样,因为两个操作系统都支持该调用。在 Windows 中,这应该会有所帮助:http://msdn.microsoft.com/en-us/library/ms682499.aspx

    【讨论】:

      【解决方案6】:

      MSDN 文档说 如果在 Windows 程序中使用,_popen 函数会返回导致程序无限期停止响应的无效文件指针。 _popen 在控制台应用程序中正常工作。要创建重定向输入和输出的 Windows 应用程序,请参阅在 Windows SDK 中创建具有重定向输入和输出的子进程。

      【讨论】:

        【解决方案7】:

        您可以使用system(),如:

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

        其中ls 是列出文件夹歌曲内容的命令名称,song 是当前目录中的文件夹。生成的文件song.txt 将在当前目录中创建。

        【讨论】:

        • 如果我想将其他程序的输出重定向到一个文件中怎么办?不是操作系统命令
        • 不,这是一种非常糟糕的做法。正确使用管道,不要在文件系统中留下临时文件。
        【解决方案8】:
        //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;
        }
        

        【讨论】:

        • 它是什么语言?肯定不是 C (string.resize?)
        • 看起来像 C++ :(
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多