Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Solved QProcess::readAll and QProcess::readAllStandardOutput both return an empty string after QProcess::write() is run

    General and Desktop
    qprocess readline stdio qt 5.7 qtcreator
    8
    15
    15246
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • CybeX
      CybeX last edited by

      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 by QProcess::write().

      Here I get lost! -> No output is received. from readAll() and readAllStandardOutput(), both are empty.

      I need the output: particularly the echo $? for later processing, but don't get anything since readAll() and readAllStandardOutput() returns empty strings

      To 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 script

      QString 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 the echo $? 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?

      1 Reply Last reply Reply Quote 0
      • dheerendra
        dheerendra Qt Champions 2022 last edited by

        Did u start event loop before waiting for the response to come from your external processes?

        Dheerendra
        @Community Service
        Certified Qt Specialist
        http://www.pthinks.com

        CybeX 1 Reply Last reply Reply Quote 3
        • CybeX
          CybeX @dheerendra last edited by

          @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!

          jsulm 1 Reply Last reply Reply Quote 0
          • jsulm
            jsulm Lifetime Qt Champion @CybeX last edited by

            @CybeX After writing you should first wait for readyRead.
            Instead you read just after writing:

            p->write(QString(input + QString("\n")).toLatin1()); 
            qDebug() << p->readAll();
            qDebug() << p->readAllStandardOutput();
            

            https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply Reply Quote 0
            • V
              VRonin last edited by VRonin

              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;
              }
              

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              CybeX 1 Reply Last reply Reply Quote 5
              • CybeX
                CybeX @VRonin last edited by

                @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...

                1 Reply Last reply Reply Quote 0
                • V
                  VRonin last edited by

                  put QObject:: in front, edited the code above

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  CybeX 1 Reply Last reply Reply Quote 0
                  • CybeX
                    CybeX @VRonin last edited by

                    @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);
                                                                                         ^
                    
                    1 Reply Last reply Reply Quote 0
                    • V
                      VRonin last edited by

                      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#finished

                      so instead of &QProcess::finished use static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished)

                      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                      ~Napoleon Bonaparte

                      On a crusade to banish setIndexWidget() from the holy land of Qt

                      1 Reply Last reply Reply Quote 1
                      • T
                        tarod.net last edited by

                        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
                        

                        "Individually, we are one drop. Together, we are an ocean."

                        CybeX sitesv 2 Replies Last reply Reply Quote 2
                        • CybeX
                          CybeX @tarod.net last edited by CybeX

                          Original SO thread

                          1 Reply Last reply Reply Quote 0
                          • sitesv
                            sitesv @tarod.net last edited by

                            @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?

                            JonB 1 Reply Last reply Reply Quote 0
                            • JonB
                              JonB @sitesv last edited by

                              @sitesv said in QProcess::readAll and QProcess::readAllStandardOutput both return an empty string after QProcess::write() is run:

                              Is this correct?

                              As code? No.

                              sitesv 1 Reply Last reply Reply Quote 0
                              • sitesv
                                sitesv @JonB last edited by

                                @JonB I don't know why this example does the output like this....

                                1 Reply Last reply Reply Quote 0
                                • B
                                  Bitbrat last edited by

                                  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();
                                      }
                                  }
                                  
                                  1 Reply Last reply Reply Quote 0
                                  • First post
                                    Last post