我正在为练习写一个婴儿计划。我想要完成的基本上是一个简单的小GUI,它显示服务(对于Linux);使用按钮启动,停止,启用和禁用服务(类似于Windows中的msconfig应用程序“服务”选项卡)。我在Fedora 21上使用C ++和Qt Creator。
我想用C ++创建GUI,并通过调用bash脚本在服务列表中填充GUI,并在按钮点击时调用bash脚本来执行相应的操作(启用,禁用等)
但是当C ++ GUI调用bash脚本(使用system("path/to/script.sh")
)时,返回值仅用于退出成功。 如何接收脚本本身的输出,以便我可以依次使用它在GUI上显示?
对于概念性示例:如果我试图将(systemctl --type service | cut -d " " -f 1
)的输出显示到我用C ++创建的GUI中,我将如何进行此操作?这甚至是我正在努力完成的正确方法吗?如果没有,
我已经找到了解决此问题的方法,但我找不到有关如何将值从>> Bash 返回到 C ++的信息,只知道如何调用来自C ++的Bash脚本。
答案 0 :(得分:8)
我们将在此处利用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重定向到stdout,并在命令末尾加2>&1
。
Here是关于popen
的文档。快乐的编码:)
答案 1 :(得分:4)
您必须使用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;
}
答案 2 :(得分:3)
漫长的方法 - 让您完全控制子进程的stdin
,stdout
和stderr
,代价是相当复杂 - 涉及使用{{1} }和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
现在,您的父进程可以完全控制子进程的std i / o,并且必须安全地复用 close(childStdin[0]); // parent cannot read from stdin
close(childStdout[1]); // parent cannot write to stdout/stderr
close(childStderr[1]);
,childStdin[1]
和childStdout[0]
,同时还要监视{ {1}}并最终使用childStderr[0]
- 系列调用来检查进程终止代码。 SIGCLD
特别适合在异步处理std i / o时处理wait
。当然,请参阅pselect
或SIGCLD
。
如果您要合并孩子的select
和poll
,只需stdout
并完全摆脱stderr
。
手册页应填写此处的空白。如果你需要它,这就是困难的方式。