简体   繁体   English

使用 QProcess 管道(或命令链)

[英]Piping (or command chaining) with QProcess

I'm using Qt and bash over it, need to execute something like:我正在使用 Qt 并对其进行 bash,需要执行如下操作:

bash: cat file | grep string

in Qt:在 Qt 中:

QString cmd = "cat file | grep string";
QProcess *process = new QProcess;
process->start(cmd);
process->waitForBytesWritten();
process->waitForFinished();
qDebug() << process->readAll();

The problem is in pipe ("|"), and process returs nothing.问题出在管道(“|”)中,并且进程没有返回任何内容。 If there is no ("|"), like如果没有(“|”),比如

"cat file" 

everything is ok.一切正常。 I tried smth.我试过了。 like

"cat file \\| grep string", 
"cat file \| grep string" 

but result is the same.但结果是一样的。 If I copy the command and run it in bash everything is ok.如果我复制命令并在 bash 中运行它,一切正常。

QString::toAscii().data()

and other transforms also have bad result.和其他转换也有不好的结果。

The problem is you cannot run a system command with QProcess, but only a single process.问题是您不能使用 QProcess 运行系统命令,而只能运行单个进程。 So the workaround will be to pass your command as an argument to bash:因此,解决方法是将您的命令作为参数传递给 bash:

process.start("bash", QStringList() << "-c" << "cat file | grep string");

The quick and dirty hack would be this:快速而肮脏的黑客将是这样的:

QString cmd = "/bin/sh -c \"cat file | grep string\"";

You could also avoid the escaping in there with C++11's R"" , but the point is that do not use bash in there because that will make it only work with bash.您也可以避免使用 C++11 的R""进行转义,但重点是不要在其中使用bash ,因为这将使其仅适用于 bash。 It will not work on embedded with busybox without bash, just ash, or any other common desktop shell.它不能在没有 bash、只有 ash 或任何其他常见桌面 shell 的情况下嵌入 busybox。

/bin/sh is usually a symlink to the shell interpreter used, so that will eventually work. /bin/sh通常是所使用的 shell 解释器的符号链接,因此最终会起作用。

BUT!但是!

I think you are thinking a bit too low-level when using a high-level C++/OOP framework such as Qt.我认为在使用高级 C++/OOP 框架(如 Qt)时,您的想法有点太低级了。 I would not recommend to invoke the commands in the low-level way when you run it from bash.当您从 bash 运行它时,我不建议以低级方式调用命令。 There is some dedicated high-level convenience API for this use case.此用例有一些专用的高级便利 API。

Based on the official documentation , QProcess is supposed to work for pipe'd commands:根据官方文档,QProcess 应该适用于管道命令:

void QProcess::setStandardOutputProcess(QProcess * destination) void QProcess::setStandardOutputProcess(QProcess * destination)

Pipes the standard output stream of this process to the destination process' standard input.将此进程的标准输出流通过管道传输到目标进程的标准输入。

In other words, the command1 |换句话说,command1 | command2 shell command command can be achieved in the following way: command2 shell command 命令可以通过以下方式实现:

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;

This is not the main point, but a useful suggestion: do not use QString::toAscii() .这不是重点,而是一个有用的建议:不要使用QString::toAscii() That API has been deprecated in Qt 5.该 API 在 Qt 5 中已被弃用。

The problem is that when you call process->start(cmd), the commands following the the call to cat are all interpreted as arguments to cat, so the pipe is not doing what you're expecting.问题是当你调用 process->start(cmd) 时,调用 cat 之后的命令都被解释为 cat 的参数,所以管道没有做你期望的。 If you start with a call to bash with a parameter of a string, you should get what you want: -如果您从使用字符串参数调用 bash 开始,您应该得到您想要的:-

QString cmd = "bash -c \"cat file | grep string\"";

Alternatively, you could just call "cat file" and do the search on the returned QString when you read the output from the QProcess或者,当您从 QProcess 读取输出时,您可以调用“cat file”并在返回的 QString 上进行搜索

how about this :这个怎么样:

QString program = "program";
QStringList arguments;

download = new QProcess(this);
download->start(program, arguments);

If Google brought you here and you are using PyQt5 or PySide2如果谷歌把你带到这里并且你使用的是 PyQt5 或 PySide2

        process1 = QProcess()
        process2 = QProcess()
        process1.setStandardOutputProcess(process2)
        process1.start(cat, [file])
        process2.start(grep, [string])   

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM