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

Проблема в pipe ( "|" ), и процесс ничего не возвращает. Если нет ( "|" ), например

"cat file" 

все в порядке. Я пробовал что-то. как

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

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

QString::toAscii().data()

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

Ответ 1

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

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

Ответ 2

Быстрый и грязный взлом будет следующим:

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

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

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

НО!

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

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

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.

Ответ 3

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

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

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

Ответ 4

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

QString program = "program";
QStringList arguments;

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