QProcess::readAll and QProcess::readAllStandardOutput both return an empty string after QProcess::write() is run
-
Hi all
note: this might become confusing, please bare with me!
To get a basic sense of what I want to do:
QProcess runs a command by
QProcess::start("sh -c \"cd /tmp/tempdir ; ./my_script --option file.txt ; echo $?\" ")
The script expects input from the user (a password),
QProcess::readAll()
confirms the script's input request. The input is given byQProcess::write()
.Here I get lost! -> No output is received. from
readAll()
andreadAllStandardOutput()
, both are empty.I need the output: particularly the
echo $?
for later processing, but don't get anything sincereadAll()
andreadAllStandardOutput()
returns empty stringsTo me there are several possible issues to cause this, maybe more than one:
- The script does not receive this input
- The script receives the input, but expects a "return key press"
- The script receives the input, QProcess::write automatically does a "return key press", the script continues and finishes but QProcess does not read this output
The Code:
// please ignore the messiness of the code, a placed a number of debugs just to see the code response.
cmd = "cd /tmp/tempdir ; ./my_script --option file.txt ; echo $?" (without quotes)
input => required input for scriptQString gen_serv::runCommand(QString cmd, QString input){ Process *p = new QProcess(parent); p->setProcessChannelMode(QProcess::MergedChannels); // p->start("sh ", QStringList() << " -c " << cmd); QString c = QString("sh -c \"" + cmd + "\" "); p->start(c); <---- ACTUAL COMMAND : sh -c "cd /tmp/tempdir ; ./my_script --option file.txt ; echo $?" if (p->waitForStarted()) { if (!p->waitForReadyRead()) { qDebug(log_lib_gen_serv) << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); } if (!p->waitForFinished(1000)) { qDebug() << p->readAll(); qDebug() << p->readAllStandardOutput(); //p->write(input.toLatin1()); p->write(QString(input + QString("\n")).toLatin1()); <--- added this "\n" incase the process/console was waiting for a return press, thus the /n should satisfy the return requirement qDebug() << p->readAll(); qDebug() << p->readAllStandardOutput(); if (!p->waitForFinished()) { qDebug() << p->readAll(); qDebug() << p->readAllStandardOutput(); qDebug(log_lib_gen_serv) << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); } qDebug() << p->readAll(); qDebug() << p->readAllStandardOutput(); } QString s = QString(p->readAll() + p->readAllStandardOutput()); return s; } else{ qDebug(log_lib_gen_serv) << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString(); } p->waitForFinished(); p->kill(); return QString(); }
Please note:
The script is long and complicated, however it returns a message "done" if successfully executed and an exit code for each case.
Thus theecho $?
should capture and return this for processing i.e.return s
I hope this makes sense, any suggestions how I can attempt to solve this issue?
-
Did u start event loop before waiting for the response to come from your external processes?
-
@dheerendra hi, thanks for the response.
Event loop? This is all the code related to the process.
If you could provide an example on a possible event loop, I believe it would be of much use
Thanks!
-
why, oh why, did The Lord invent the synchronous API?! it's an aberration!
QString gen_serv::runCommand(const QString& cmd, const QString& input){ QString result; QEventLoop looper; Process *p = new QProcess(&looper); p->setProcessChannelMode(QProcess::MergedChannels); QObject::connect(p,&QProcess::finished,&looper,&QEventLoop::quit); QObject::connect(p,&QProcess::errorOccurred,[&result]()->void{qDebug("Error in Process"); result.clear();}); QObject::connect(p,&QProcess::errorOccurred,&looper,&QEventLoop::quit); QObject::connect(p,&QProcess::started,[p,&input]()->void{p->write((input +'\n').toLatin1());}); QObject::connect(p,&QProcess::readyReadStandardOutput,[p,&result]()->void{result+=p->readAllStandardOutput();}); const QString c = QString("sh -c \"" + cmd + "\" "); p->start(c); looper.exec(); return result; }
-
@VRonin said in QProcess::readAll and QProcess::readAllStandardOutput both return an empty string after QProcess::write() is run:
hi
Thank you very much for the solution!
Just one small issue:
error: ‘connect’ was not declared in this scope connect(p,&QProcess::finished,&looper,&QEventLoop::quit); ^
Not so sure about this one...
-
@VRonin hi, same 'same' error
My includes for what it is worth
#include <QCoreApplication> #include <QLoggingCategory> #include <QTextStream> #include <QProcess> #include <QString> #include <QVariant> #include <QDebug> #include <QObject> #include <QEventLoop>
Edited Code as give above:
QString runCommand(const QString& cmd, const QString& input){ //I ignore cmd for testing purposes. I use a straightup cd to script and execute QString result; QEventLoop looper; QProcess *p = new QProcess(&looper); p->setProcessChannelMode(QProcess::MergedChannels); QObject::connect(p,&QProcess::finished,&looper,&QEventLoop::quit); QObject::connect(p,&QProcess::errorOccurred,[&result]()->void{qDebug("Error in Process"); result.clear();}); QObject::connect(p,&QProcess::errorOccurred,&looper,&QEventLoop::quit); QObject::connect(p,&QProcess::started,[p,&input]()->void{p->write((input +'\n').toLatin1());}); QObject::connect(p,&QProcess::readyReadStandardOutput,[p,&result]()->void{result+=p->readAllStandardOutput();}); const QString c = QString("sh -c \" cd /home/dev; ./script\" "); p->start(c); looper.exec(); return result; }
Error:
main.cpp:296: error: no matching function for call to ‘QObject::connect(QProcess*&, <unresolved overloaded function type>, QEventLoop*, void (QEventLoop::*)())’ QObject::connect(p,&QProcess::finished,&looper,&QEventLoop::quit); ^
-
My bad. if it happens again look at the documentation for the signal and/or slot (depending where
<unresolved overloaded function type>
appears). In this case: http://doc.qt.io/qt-5/qprocess.html#finishedso instead of
&QProcess::finished
usestatic_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished)
-
I would like to post my Stack Oveflow answer. It's actually an example where we write the name and get also the output given by the script.
Code:
#include <QCoreApplication> #include <QProcess> #include <QDebug> class MyProcess : public QProcess { Q_OBJECT public: MyProcess(QObject *parent = 0); ~MyProcess() {} public slots: void myReadyRead(); void myReadyReadStandardOutput(); }; MyProcess::MyProcess(QObject *parent) { connect(this,SIGNAL(readyRead()), this,SLOT(myReadyRead())); connect(this,SIGNAL(readyReadStandardOutput()), this,SLOT(myReadyReadStandardOutput())); } void MyProcess::myReadyRead() { qDebug() << Q_FUNC_INFO; } void MyProcess::myReadyReadStandardOutput() { qDebug() << Q_FUNC_INFO; // Note we need to add \n (it's like pressing enter key) this->write(QString("myname" + QString("\n")).toLatin1()); // Next line no required // qDebug() << this->readAll(); qDebug() << this->readAllStandardOutput(); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); MyProcess *myProcess = new MyProcess(); QString program = "/home/fran/code/myscript.sh"; myProcess->start("/bin/sh", QStringList() << program); a.exec(); } #include "main.moc"
Script:
echo "enter your name:" read n if [ ! -z "$n" ]; then echo "success" exit 0; else echo "failed" exit 1; fi
-
@tarod-net
Hi!
I have this output without input stream from keyboard:void MyProcess::myReadyRead() void MyProcess::myReadyReadStandardOutput() "enter your name\n" void MyProcess::myReadyRead() void MyProcess::myReadyReadStandardOutput() "success\n"
Is this correct?
-
QProcess has quite extensive support for synchronous use.
#include <QCoreApplication> #include <QDebug> #include <QProcess> int main(int argc, char **argv) { QCoreApplication app(argc, argv); QProcess process; process.start("ls", {"-l"}); if (process.waitForFinished()) { qDebug() << "returned:" << process.readAllStandardOutput(); } else { qDebug() << process.errorString(); } process.start("ls", {"-l"}); while (process.waitForReadyRead()) { while (process.canReadLine()) qDebug() << process.readLine().trimmed(); } }