Конвейер (или цепочка команд) с QProcess

Я использую Qt и bash над ним, нужно выполнить что-то вроде:

bash: cat file | grep string

in 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()

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


person Konstantin Ivanov    schedule 03.01.2014    source источник
comment
Попробуйте cmd = "bash -c 'cat file | grep string'";   -  person user000001    schedule 03.01.2014
comment
@LaszloPapp Никаких аргументов ... Поскольку есть специальный API, ваш ответ лучше. С другой стороны, вызов оболочки может позволить более сложные команды, например. используя подстановку процессов, подстановку оболочки и т. д., поэтому при некоторых условиях это может иметь некоторые преимущества.   -  person user000001    schedule 03.01.2014


Ответы (5)


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

process.start("bash", QStringList() << "-c" << "cat file | grep string");
person Dmitry Markin    schedule 03.01.2014
comment
Почему бы не использовать QProcess для конвейерных команд с высокоуровневым API в соответствии с моим ответом? :-) - person lpapp; 03.01.2014
comment
Ваш ответ в порядке, это всего лишь обходной путь. - person Dmitry Markin; 03.01.2014
comment
Что вы подразумеваете под системной командой? Вы, вероятно, имели в виду что-то более конкретное, например команду оболочки. - person lrineau; 03.01.2014
comment
Я имел в виду system вызов типа os.system() в Python или system из <cstdlib>. - person Dmitry Markin; 03.01.2014
comment
@DmitryMarkin: OT, но не используйте os.system() в python. Люди должны использовать модуль подпроцесса в соответствии с документацией. - person lpapp; 03.01.2014

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

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

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

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

НО!

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

Согласно официальной документации, предполагается, что QProcess работает для канала d команды:

void QProcess::setStandardOutputProcess(QProcess * пункт назначения)

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

Другими словами, команда1 | Команда командной оболочки command2 может быть достигнута следующим образом:

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.

person lpapp    schedule 03.01.2014
comment
Я хотел бы использовать этот метод, но проблема для меня в том, что он не работал так, как это сделал принятый ответ. Я не передаю команды, а просто пытаюсь выполнить две последовательные команды: gcc *.c; ./a.out argv[1] ... когда я использую ваш код с setStandardOutputProcess, я получаю странные результаты. - person 7kemZmani; 28.07.2016
comment
Любые мысли о длительных процессах? Что, если процесс 1 является сеансом telnet, и я хочу, чтобы процесс 2 переписал вывод этого сеанса telnet процесса 1. Я бы по-прежнему отправлял команды в процесс 1, но нужно ли, чтобы вывод выводился в процесс 2? Код приветствуется. - person RoundSparrow hilltx; 30.08.2017

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

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

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

person TheDarkKnight    schedule 03.01.2014
comment
команда работает нормально, однако вывод, который я получаю, немного мусорный... для этой команды netstat -i | grep enss33 | awk '{print $3}', результат будет 0x804d2045085, должно быть всего 5085... - person krisdigitx; 20.06.2014
comment
@krisdigitx, я подозреваю, что это может быть связано с тем, как команда awk передается с символами '. Если вы удалите awk и просто подключитесь к grep, будет ли это работать так, как ожидалось? Если это работает, добавьте awk, но избегайте кавычек. - person TheDarkKnight; 20.06.2014
comment
Я избежал одинарных кавычек... все тот же вывод... fpaste.org/111471/32714861 - person krisdigitx; 20.06.2014
comment
У меня также работает Qdebug, использование выходной переменной не имеет никакого значения для вывода с использованием cout также ..... поэтому я думаю, что проблема заключается в том, что cout обрабатывает вывод .... - person krisdigitx; 20.06.2014
comment
С Qt я не вижу причин использовать cout. Вы могли бы также использовать fprintf и посмотреть, имеет ли это значение. Рад, что теперь работает ;О) - person TheDarkKnight; 20.06.2014
comment
вывод cout на самом деле правильный, в программе есть что-то еще, что вызывает это... fpaste.org/111490 /03274758 - person krisdigitx; 20.06.2014
comment
Давайте продолжим обсуждение в чате. - person TheDarkKnight; 20.06.2014

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

QString program = "program";
QStringList arguments;

download = new QProcess(this);
download->start(program, arguments);
person bulldog68    schedule 09.08.2015
comment
Подумайте о том, чтобы добавить больше деталей, чтобы сделать этот ответ лучше, чем текущий. - person Victor Polevoy; 09.08.2015

Если Google привел вас сюда и вы используете PyQt5 или PySide2

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