从bash脚本返回输出到调用C ++函数

我正在写一个实践的宝贝计划。 我试图完成的基本上是一个简单的小graphics用户界面,显示服务(对于Linux); 使用button启动,停止,启用和禁用服务(与Windows中的msconfig应用程序“服务”选项卡类似)。 我在Fedora 21上使用C ++与Qt Creator。

我想用C ++创buildGUI,并通过调用bash脚本来填充GUI的服务列表,并在button单击时调用bash脚本来执行相应的操作(启用,禁用等)

但是,当C ++ GUI调用bash脚本(使用system("path/to/script.sh") )时,返回值仅用于退出成功。 如何接收脚本本身的输出 ,以便我可以反过来使用它在GUI上显示?

对于概念性的例子:如果我试图将( systemctl --type service | cut -d " " -f 1 )的输出显示到我在C ++中创build的GUI中,我该如何去做呢? 这是甚至正确的方式来做我想要完成的? 如果不,

  1. 什么是正确的方式? 和
  2. 使用我目前的方法还有办法做到这一点吗?

我已经find了这个问题的解决scheme,但我找不到有关如何 Bash返回值 C ++的信息,只有如何从C ++ 调用 Bash脚本。

我们将在这里利用popen函数。

 std::string exec(char* cmd) { FILE* pipe = popen(cmd, "r"); if (!pipe) return "ERROR"; char buffer[128]; std::string result = ""; while(!feof(pipe)) { if(fgets(buffer, 128, pipe) != NULL) result += buffer; } pclose(pipe); return result; } 

该函数将一个命令作为参数,并以string返回输出。

注意:不会捕获stderr! 一个快速简便的解决方法是 stderr 重定向到标准输出,在命令结尾处使用2>&1

这里是popen文档。 快乐编码:)

您必须使用popen而不是system来运行命令,然后循环返回的文件指针。

这里是命令ls -l一个简单例子

 #include <stdio.h> #include <stdlib.h> int main() { FILE *process; char buff[1024]; process = popen("ls -l", "r"); if (process != NULL) { while (!feof(process)) { fgets(buff, sizeof(buff), process); printf("%s", buff); } pclose(process); } return 0; } 

冗长的方法 – 以相当大的复杂性为代价,可以完全控制子进程的stdinstdoutstderr ,这涉及到直接使用forkexecve

  1. fork之前,设置你的端点进行通信 – pipe工作正常,或socketpair 。 我假设你已经调用了如下的东西:

     int childStdin[2], childStdout[2], childStderr[2]; pipe(childStdin); pipe(childStdout); pipe(childStderr); 
  2. fork之后,在execve之前的子进程中:

     dup2(childStdin[0], 0); // childStdin read end to fd 0 (stdin) dup2(childStdout[1], 1); // childStdout write end to fd 1 (stdout) dup2(childStderr[1], 2); // childStderr write end to fd 2 (stderr) 

    然后关闭所有childStdinchildStdoutchildStderr

  3. fork之后,在父进程中:

      close(childStdin[0]); // parent cannot read from stdin close(childStdout[1]); // parent cannot write to stdout/stderr close(childStderr[1]); 

现在,您的父进程已完全控制子进程的std I / O,并且必须安全地复用childStdin[1]childStdout[0]childStderr[0] ,同时还监视SIGCLD并最终使用childStderr[0]系列调用来检查进程终止代码。 pselect在处理std I / O时异步处理SIGCLD特别好。 另请参阅selectpoll当然。

如果你想合并孩子的stdoutstderr ,只需要dup2(childStdout[1], 2)并完全摆脱childStderr

手册页应该填写从这里的空白。 所以这是困难的方式,如果你需要它。