如何在 C++ 中获取 linux 命令输出字符串和输出状态

Posted

技术标签:

【中文标题】如何在 C++ 中获取 linux 命令输出字符串和输出状态【英文标题】:how to get linux command output string and output status in c++ 【发布时间】:2013-03-23 18:16:38 【问题描述】:

我想获取 Linux 命令的输出字符串以及 C++ 程序中的命令输出状态。我正在我的应用程序中执行 Linux 命令。

例如: 命令:

rmdir abcd

命令输出字符串:

rmdir: 删除 `abcd' 失败: 没有这样的文件或目录

命令状态:

1(表示命令失败)

我尝试使用 Linux 函数 system() 给出输出状态,函数 popen() 给出命令的输出字符串,但是这两个函数都没有给我 Linux 命令的输出字符串和输出状态。

【问题讨论】:

如果您使用的是 C++,为什么问题标记为 C? 【参考方案1】:

在上面 Piotr Zierhoffer 回答的基础上,这里有一个函数可以做到这一点,并且还可以恢复 stdout 和 stderr 的原始状态。

// Execute command <cmd>, put its output (stdout and stderr) in <output>,
// and return its status
int exec_command(string& cmd, string& output) 
    // Save original stdout and stderr to enable restoring
    int org_stdout = dup(1);
    int org_stderr = dup(2);

    int pd[2];
    pipe(pd);

    // Make the read-end of the pipe non blocking, so if the command being
    // executed has no output the read() call won't get stuck
    int flags = fcntl(pd[0], F_GETFL);
    flags |= O_NONBLOCK;

    if(fcntl(pd[0], F_SETFL, flags) == -1) 
        throw string("fcntl() failed");
    

    // Redirect stdout and stderr to the write-end of the pipe
    dup2(pd[1], 1);
    dup2(pd[1], 2);
    int status = system(cmd.c_str());
    int buf_size = 1000;
    char buf[buf_size];

    // Read from read-end of the pipe
    long num_bytes = read(pd[0], buf, buf_size);

    if(num_bytes > 0) 
        output.clear();
        output.append(buf, num_bytes);
    

    // Restore stdout and stderr and release the org* descriptors
    dup2(org_stdout, 1);
    dup2(org_stderr, 2);
    close(org_stdout);
    close(org_stderr);

    return status;

【讨论】:

【参考方案2】:

您可以使用popen 系统调用,它将输出重定向到文件,您可以从文件将输出重定向到字符串。喜欢:

    char buffer[MAXBUF] = 0;
    FILE *fd = popen("openssl version -v", "r");
    if (NULL == fd)
    
        printf("Error in popen");
        return;
    
    fread(buffer, MAXBUF, 1, fd);
    printf("%s",buffer);

    pclose(fd);

更多信息请阅读man页面popen

【讨论】:

【参考方案3】:

最简单的解决方案是使用system,并将标准输出和标准错误重定向到一个临时文件,您可以稍后将其删除。

【讨论】:

【参考方案4】:

输出字符串在标准输出或标准错误描述符中(分别为 1 或 2)。

您必须将这些流(查看 dupdup2 函数)重定向到可以读取它们的位置(例如 - POSIX pipe)。

在 C 中我会做这样的事情:

int pd[2];
int retValue;
char buffer[MAXBUF] = 0;
pipe(pd);
dup2(pd[1],1);
retValue = system("your command");
read(pd[0], buffer, MAXBUF);

现在,您在缓冲区中有(部分)输出,在 retValue 中有返回码。

或者,您可以使用来自exec 的函数(即execve)并通过waitwaitpid 获取返回值。

更新:这将只重定向标准输出。要重定向标准错误,请使用dup2(pd[1],1)

【讨论】:

你确定这行得通吗?我认为system() 在 shell 进程退出之前不会返回。此外,如果孩子的输出很大,它对stdout 的写入可能会阻塞,从而导致死锁。我想如果它确实有效,我不会感到惊讶,因为当孩子退出时数据已经在管道中,但死锁仍然可能是一个问题。 好吧,如果输出的大小大于管道的大小(我的机器上默认为 65536),这可能会阻塞。如果这是预期的,那么 fork + exec 是首选方式。但如果不是(我的意思是,如果情况已知并且输出大小是有界的),那为什么还要麻烦呢? :) 当然,很公平。 +1 有趣的策略 很难想象输出大小确实受到限制的情况。这里通常的解决方案是将命令的输出重定向到一个临时文件,然后读取它。 好吧,我从来没有用过“保证”这个词。通过“绑定”,我想到您知道输出的大小是合理的,可能是因为您是生成输出的人。当然,总是有可能发生灾难,bash 失败,fork 失败,!ANY!失败,但通常我们只是检查合理的条件。如果系统不是关键/通用/广泛使用,那么使用您想到的第一个选项可能足够。但无论如何我投票支持你的答案,因为我们可以假设你有足够的磁盘存储空间来输出:P【参考方案5】:

不幸的是,在 Linux 上的 C 语言中没有简单的方法可以做到这一点。 Here's 一个如何正确读/写子进程的stdout/stderr/stdin的例子。

当您想接收退出代码时,您必须使用waitpid(完整示例在提供的页面底部提供):

endID = waitpid(childID, &status, WNOHANG|WUNTRACED);

现在你只需要把这两者结合起来:)

还有一本很棒的免费书籍,名为 Advanced Linux Programming (ALP),其中包含详细信息关于这类问题可用here.

【讨论】:

而在advancedlinuxprogramming.com 中有一整章关于这些问题 @BasileStarynkevitch 啊,ALP,完全忘记了...我已经添加它来回答。

以上是关于如何在 C++ 中获取 linux 命令输出字符串和输出状态的主要内容,如果未能解决你的问题,请参考以下文章

用Java如何实现获取linux控制台的输出(分很多)

如何获取一个程序的输出并将其用作 C++ 上另一个程序的输入?

如何在 c++ linux 中获取 3g 调制解调器信号强度?

如何在linux中识别一个进程是java还是c或c++进程?

如何在 C++ 中获取、存储和打印非英语字符串

如何在 C++ 中获取非英文字符