我正在写一个实践的宝贝计划。 我试图完成的基本上是一个简单的小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中,我该如何去做呢? 这是甚至正确的方式来做我想要完成的? 如果不,
我已经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; }
冗长的方法 – 以相当大的复杂性为代价,可以完全控制子进程的stdin
, stdout
和stderr
,这涉及到直接使用fork
和execve
。
在fork
之前,设置你的端点进行通信 – pipe
工作正常,或socketpair
。 我假设你已经调用了如下的东西:
int childStdin[2], childStdout[2], childStderr[2]; pipe(childStdin); pipe(childStdout); pipe(childStderr);
在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)
然后关闭所有的childStdin
, childStdout
和childStderr
。
在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
特别好。 另请参阅select
或poll
当然。
如果你想合并孩子的stdout
和stderr
,只需要dup2(childStdout[1], 2)
并完全摆脱childStderr
。
手册页应该填写从这里的空白。 所以这是困难的方式,如果你需要它。