我正在使用以下代码来尝试读取结果 df Linux 中的命令使用 popen.

#include <iostream> // file and std I/O functions

int main(int argc, char** argv) {
    FILE* fp;
    char * buffer;
    long bufSize;
    size_t ret_code;

    fp = popen("df", "r");
    if(fp == NULL) { // head off errors reading the results
        std::cerr << "Could not execute command: df" << std::endl;
        exit(1);
    }

    // get the size of the results
    fseek(fp, 0, SEEK_END);
    bufSize = ftell(fp);
    rewind(fp);

    // allocate the memory to contain the results
    buffer = (char*)malloc( sizeof(char) * bufSize );
    if(buffer == NULL) {
        std::cerr << "Memory error." << std::endl;
        exit(2);
    }

    // read the results into the buffer
    ret_code = fread(buffer, 1, sizeof(buffer), fp);
    if(ret_code != bufSize) {
        std::cerr << "Error reading output." << std::endl;
        exit(3);
    }

    // print the results
    std::cout << buffer << std::endl;

    // clean up
    pclose(fp);
    free(buffer);
    return (EXIT_SUCCESS);
}

此代码给我一个“内存错误”,退出状态为“2”,所以我可以看到 在哪里 它失败了,我只是不明白 为什么.

我从我找到的示例代码中将其放在一起 Ubuntu 论坛C++ 参考, ,所以我没有嫁给它。如果有人可以建议一种更好的方法来读取 system() 调用的结果,我愿意接受新想法。

编辑原文: 好的, bufSize 呈阴性,现在我明白为什么了。你不能像我天真地尝试那样随机访问管道。

我不可能是第一个尝试这样做的人。有人可以给出(或指出)一个如何将 system() 调用的结果读取到 C++ 变量中的示例吗?

有帮助吗?

解决方案

为什么std::malloc()会失败?

显而易见的原因是<!>“;因为std::ftell()返回了一个负的有符号数字,然后被视为一个巨大的无符号数字<!>”。

根据文档df返回-1失败了。它失败的一个明显原因是你无法在管道或FIFO中寻找

没有逃脱;如果不读取它就无法知道命令输出的长度,并且只能读取一次。你必须以块的形式阅读它,或者根据需要增长缓冲区或者动态解析。

但是,当然,您可以直接使用系统调用statvfs()可能用于获取其信息来避免整个问题:<=>。

其他提示

你这太难了。 popen(3)为标准管道文件返回常规旧的FILE *,也就是说,换行符终止记录。您可以通过在C中使用 fgets(3)来非常高效地阅读它:

#include <stdio.h>
char bfr[BUFSIZ] ;
FILE * fp;
// ...
if((fp=popen("/bin/df", "r")) ==NULL) {
   // error processing and return
}
// ...
while(fgets(bfr,BUFSIZ,fp) != NULL){
   // process a line
}

在C ++中它更容易 -

#include <cstdio>
#include <iostream>
#include <string>

FILE * fp ;

if((fp= popen("/bin/df","r")) == NULL) {
    // error processing and exit
}

ifstream ins(fileno(fp)); // ifstream ctor using a file descriptor

string s;
while (! ins.eof()){
    getline(ins,s);
    // do something
}

那里有更多的错误处理,但这就是主意。关键在于您将 的<=>视为 <=>,并逐行阅读。

我不确定你是否可以像这样fseek / ftell管道流。

您检查过bufSize的值吗? malloc失败的一个原因是疯狂大小的缓冲区。

(关于术语的注释:Unix 和 Linux 中的“系统调用”通常是指从用户空间代码调用内核函数。将其称为“结果 system() 调用”或“结果 system(3) call”会更清楚,但最好直接说“捕获进程的输出。”)

无论如何,您可以读取进程的输出,就像读取任何其他文件一样。具体来说:

  • 您可以使用以下命令启动该过程 pipe(), fork(), , 和 exec(). 。这给你一个文件描述符,然后你可以使用循环 read() 从文件描述符到缓冲区并且 close() 完成后的文件描述符。这是最低级别的选项,为您提供最大的控制权。
  • 您可以使用以下命令启动该过程 popen(), ,就像你正在做的那样。这给你一个文件流。在循环中,您可以使用从流中读取到临时变量或缓冲区 fread(), fgets(), , 或者 fgetc(), 正如 Zarawesome 的答案所示,然后处理该缓冲区或将其附加到 C++ 字符串中。
  • 您可以使用以下命令启动该过程 popen(), ,然后使用非标准 __gnu_cxx::stdio_filebuf 包装它,然后创建一个 std::istream 来自 stdio_filebuf 并像对待任何其他 C++ 流一样对待它。这是最像 C++ 的方法。这是 第1部分第2部分 这种方法的一个例子。

感谢所有花时间回答的人。一位同事向我指出了 ostringstream 课程。这里有一些示例代码,它基本上解释了我在原始问题中尝试做的事情。

#include <iostream> // cout
#include <sstream> // ostringstream

int main(int argc, char** argv) {
    FILE* stream = popen( "df", "r" );
    std::ostringstream output;

    while( !feof( stream ) && !ferror( stream ))
    {
        char buf[128];
        int bytesRead = fread( buf, 1, 128, stream );
        output.write( buf, bytesRead );
    }
    std::string result = output.str();
    std::cout << "<RESULT>" << std::endl << result << "</RESULT>" << std::endl;
    return (0);
}

回答更新中的问题:

char buffer[1024];
char * line = NULL;
while ((line = fgets(buffer, sizeof buffer, fp)) != NULL) {
    // parse one line of df's output here.
}

这还够吗?

要检查的第一件事是bufSize的值 - 如果碰巧是<!> lt; = 0,那么当你尝试在那时分配一个大小为0的缓冲区时,malloc可能会返回NULL。 / p>

另一个解决方法是让malloc为你提供一个大小为(bufSize + n)的缓冲区,其中n <!> gt; = 1,这应该可以解决这个特殊问题。

除此之外,你发布的代码是纯C而不是C ++,所以包括过度使用它。

检查你的bufSize。 ftell错误时可以返回-1,这可能导致malloc使用具有NULL值的缓冲区进行非分配。

因为popen而导致<=>失败的原因。你无法搜索管道。

管道不是随机访问。它们是顺序的,这意味着一旦你读取一个字节,管道就不会再发送给你了。显然,这意味着你无法倒回它。

如果您只想将数据输出回用户,您可以执行以下操作:

// your file opening code

while (!feof(fp))
{
char c = getc(fp);
std::cout << c;
}

这将逐个从df管道中拉出字节,并将它们直接输入输出。

现在,如果要整体访问df输出,可以将其传输到文件中并读取该文件,或者将输出连接到诸如C ++ String之类的构造中。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top