Трубопровод (или цепочка команд) с 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);