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

все отлично.
Я пытался что-то лайк

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

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

QString::toAscii().data()

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

15

Решение

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

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

Другие решения

Быстрый и грязный хак был бы такой:

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)

Передает стандартный поток вывода этого процесса к стандартному вводу процесса назначения.

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

23

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

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

В качестве альтернативы, вы можете просто вызвать «cat file» и выполнить поиск по возвращенной QString при чтении вывода из QProcess

3

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

QString program = "program";
QStringList arguments;

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