使用 QProcess 进行管道(或命令链接)
Posted
技术标签:
【中文标题】使用 QProcess 进行管道(或命令链接)【英文标题】:Piping (or command chaining) with QProcess 【发布时间】:2014-01-03 10:51:01 【问题描述】:我正在使用 Qt 和 bash,需要执行以下操作:
bash: cat file | grep string
在 Qt 中:
QString cmd = "cat file | grep string";
QProcess *process = new QProcess;
process->start(cmd);
process->waitForBytesWritten();
process->waitForFinished();
qDebug() << process->readAll();
问题出在管道 ("|") 中,进程没有返回任何内容。如果没有(“|”),比如
"cat file"
一切正常。 我试过了。喜欢
"cat file \\| grep string",
"cat file \| grep string"
但结果是一样的。如果我复制命令并在 bash 中运行它一切正常。
QString::toAscii().data()
和其他转换也有不好的结果。
【问题讨论】:
试试cmd = "bash -c 'cat file | grep string'";
@LaszloPapp 没有论据......因为有一个专用的API,你的答案会更好。另一方面,调用 shell 可能允许更复杂的命令,例如使用进程替换、shell globbing 等,因此在某些情况下它可能具有一些优势。
【参考方案1】:
问题是您不能使用 QProcess 运行系统命令,而只能运行单个进程。因此,解决方法是将您的命令作为参数传递给 bash:
process.start("bash", QStringList() << "-c" << "cat file | grep string");
【讨论】:
为什么不按照我的回答将 QProcess 用于具有高级 API 的管道命令? :-) 你的回答完全OK,这只是一种解决方法。 “系统命令”是什么意思?您可能指的是更具体的内容,例如“shell 命令”。 我的意思是system
在 Python 中调用 os.system()
或从 <cstdlib>
调用 system
。
@DmitryMarkin:OT,但不要在 python 中使用 os.system()。人们应该按照文档使用子流程模块。【参考方案2】:
快速而肮脏的黑客是这样的:
QString cmd = "/bin/sh -c \"cat file | grep string\"";
您也可以使用 C++11 的 R""
避免其中的转义,但关键是不要在其中使用 bash
,因为这将使其仅适用于 bash。在没有 bash、ash 或任何其他常见桌面 shell 的情况下,它不适用于嵌入 busybox。
/bin/sh
通常是指向所使用的 shell 解释器的符号链接,因此最终会起作用。
但是!
我认为在使用 Qt 等高级 C++/OOP 框架时,您的想法有点太低级了。当您从 bash 运行命令时,我不建议以低级方式调用命令。这个用例有一些专用的高级便利 API。
基于official documentation,QProcess 应该适用于管道命令:
void QProcess::setStandardOutputProcess(QProcess * 目的地)
将此进程的标准输出流通过管道传输到目标进程的标准输入。
换句话说,命令1 | command2 shell命令命令可以通过以下方式实现:
QProcess process1;
QProcess process2;
process1.setStandardOutputProcess(&process2);
process1.start("cat file");
process2.start("grep string");
process2.setProcessChannelMode(QProcess::ForwardedChannels);
// Wait for it to start
if(!process1.waitForStarted())
return 0;
bool retval = false;
QByteArray buffer;
while ((retval = process2.waitForFinished()));
buffer.append(process2.readAll());
if (!retval)
qDebug() << "Process 2 error:" << process2.errorString();
return 1;
qDebug() << "Buffer data" << buffer;
这不是重点,而是一个有用的建议:不要使用QString::toAscii()
。该 API 在 Qt 5 中已被弃用。
【讨论】:
我希望我能使用这种方法,但对我来说,问题是它不像接受的答案那样起作用。我不是管道命令,而只是尝试执行两个连续的命令: gcc *.c; ./a.out argv[1] ...当我将您的代码与 setStandardOutputProcess 一起使用时,我得到了奇怪的结果。 对长时间运行的进程有什么想法吗?如果 process1 是一个 telnet 会话并且我希望 process2 重写该 process1 telnet 会话的输出,该怎么办。我仍然会向 process1 发送命令,但需要将输出通过管道传输到 process2 吗?欢迎代码。 这行while ((retval = process2.waitForFinished())); buffer.append(process2.readAll());
可以是while (retval = process2.waitForFinished()) buffer.append(process2.readAll());
吗?【参考方案3】:
问题在于,当您调用 process->start(cmd) 时,调用 cat 之后的命令都被解释为 cat 的参数,因此管道没有按照您的预期执行。如果你从使用字符串参数调用 bash 开始,你应该得到你想要的:-
QString cmd = "bash -c \"cat file | grep string\"";
或者,您可以在读取 QProcess 的输出时调用“cat 文件”并在返回的 QString 上进行搜索
【讨论】:
命令运行正常,但是我得到的输出有点垃圾......对于这个命令“netstat -i | grep enss33 | awk 'print $3',它得到的结果为 0x804d2045085 ,它应该只是 5085... @krisdigitx,我怀疑这可能是由于 awk 命令是如何与 ' 字符一起传递的。如果您删除 awk 并仅通过管道连接到 grep,这是否按预期工作?如果可行,请添加 awk,但转义引号。 我已经转义了单引号...仍然是相同的输出...fpaste.org/111471/32714861 @krisdigitx 使用标准输出作为变量名可能是个坏主意。这对我有用:pastebin.com/1jZWDL0C Qdebug 也适用于我,使用“输出”变量与使用 cout 的输出也没有区别.....所以我认为问题在于 cout 处理输出......跨度> 【参考方案4】:这个怎么样:
QString program = "program";
QStringList arguments;
download = new QProcess(this);
download->start(program, arguments);
【讨论】:
考虑添加更多细节,使其成为比当前更好的答案。【参考方案5】:如果 Google 把你带到这里,而你正在使用 PyQt5 或 PySide2
process1 = QProcess()
process2 = QProcess()
process1.setStandardOutputProcess(process2)
process1.start(cat, [file])
process2.start(grep, [string])
【讨论】:
以上是关于使用 QProcess 进行管道(或命令链接)的主要内容,如果未能解决你的问题,请参考以下文章
关于 在国产麒麟系统上使用QProcess配合管道命令执行shell命令获取预期结果输出失败 的解决方法