Трубопровод (или цепочка команд) с QProcess

я использую 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" 

все ок. Я попробовал smth. как

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

но результат тот же. Если я скопирую команду и запускаю ее в bash, все в порядке.

QString::toAscii().data()

и другие преобразования также имеют плохой результат.

4 ответов


проблема в том, что вы не можете запустить системную команду с QProcess, а только один процесс. Таким образом, обходным путем будет передача вашей команды в качестве аргумента bash:

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

быстрый и грязный хак будет так:

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

вы также можете избежать побега там с C++11 в R"", но дело в том, что не используйте bash там, потому что это работает только в bash. Он не будет работать на встроенном busybox без bash, просто ash или любой другой общей настольной оболочки.

/bin/sh обычно является символической ссылкой на используемый интерпретатор оболочки, так что в конечном итоге работа.

но!

Я думаю, что вы думаете слишком низкоуровневый при использовании высокоуровневой платформы C++/OOP, такой как Qt. Я бы не рекомендовал вызывать команды на низком уровне, когда вы запускаете его из bash. Для этого случая использования существует специальный API-интерфейс высокого уровня.

на основе официальная документация, QProcess должен работать для команд pipe'D:

void QProcess:: setStandardOutputProcess(qprocess * destination)

передает стандартный выходной поток этого процесса на стандартный вход целевого процесса.

другими словами, команда command1 / 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;

это не главное, но полезное предложение: не используйте QString::toAscii(). Этот API был устаревшим в Qt 5.


проблема в том, что при вызове process->start(cmd) команды, следующие за вызовом cat, интерпретируются как аргументы cat, поэтому канал не делает то, что вы ожидаете. Если вы начинаете с вызова bash с параметром строки, вы должны получить то, что хотите: -

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

кроме того, вы можете просто вызвать "файл cat" и выполнить поиск по возвращенной QString при чтении вывода из QProcess


Как насчет этого :

QString program = "program";
QStringList arguments;

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