Конвейер (или верига на команди) с 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"" на C++11, но въпросът е, че не използвайте bash там, защото това ще го накара да работи само с bash. Няма да работи на вграден с busybox без bash, само ash или всяка друга обичайна обвивка на работния плот.

/bin/sh обикновено е символна връзка към използвания интерпретатор на обвивката, така че в крайна сметка ще работи.

НО!

Мисля, че мислите за твърде ниско ниво, когато използвате C++/OOP рамка от високо ниво като Qt. Не бих препоръчал да извиквате командите по начина на ниско ниво, когато го стартирате от bash. Има специален API за удобство на високо ниво за този случай на употреба.

Въз основа на официалната документация, QProcess трябва да работи за канал '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.

person lpapp    schedule 03.01.2014
comment
Иска ми се, ако мога да използвам този метод, но проблемът за мен е, че не работи по начина, по който приетият отговор. Не изпращам команди, а просто се опитвам да изпълня две последователни команди: gcc *.c; ./a.out argv[1] ... когато използвам вашия код с setStandardOutputProcess, получавам странни резултати. - person 7kemZmani; 28.07.2016
comment
Някакви мисли за дълготрайни процеси? Ами ако процес1 е телнет сесия и искам процес2 да пренапише изхода от тази телнет сесия на процес1. Все пак бих изпратил команди до process1, но трябва да препраща изход към process2? Код добре дошъл. - 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
@krisdigitx Използването на stdout като име на променлива вероятно е лоша идея. Това работи за мен: pastebin.com/1jZWDL0C - person TheDarkKnight; 20.06.2014
comment
Qdebug работи и за мен, използването на изходна променлива не направи разлика с изхода, използвайки също cout.....така че мисля, че проблемът е в това, че cout обработва изхода.... - person krisdigitx; 20.06.2014
comment
С Qt не виждам причина да използвам cout. Можеше също да използваш fprintf и да видиш дали това има значение. Радвам се, че вече работи ;O) - person TheDarkKnight; 20.06.2014
comment
изходът на cout всъщност е правилен, има нещо друго в програмата, което причинява това...fpaste.org/111490 /03274758 - person krisdigitx; 20.06.2014
comment
Нека продължим тази дискусия в чата. - person TheDarkKnight; 20.06.2014

@KlasLindbäck Опитах и ​​не помага
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