reading and writing to QProcess in Qt Console Application

Noted: this appears to be a specific issue question but hopefully it can be edited for all to related to

I need to interact with a QProcess object.

The Problem:

I am not getting any output from QProcess after calling QProcess:write(input)

More Info:

Going through the doc pages led me to create an example below:

I have a script requesting user input, and finally displaying and appropriate message based on the user input.

Testing:

After adding a "log" feature to my script for testing, the following occurs:

  • script executes
  • script requests user input (confirmed by the 'first' qDebug() << p->readAll() )
  • script accepts input from QProcess (confirmed by script 'log output')
  • After this, no output is received. The following 2 debug statements both fire (ie wait 30s each)

    if (!p->waitForReadyRead()) {
        qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
    }
    if (!p->waitForFinished()) {
        qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
    }
    

    Followed by:

    QString s = QString(p->readAll() + p->readAllStandardOutput());
    

    where s is an empty string.

    The issue is s should contain either "success" or "failed"

    Calling Code:

    QString cmd = QString("sh -c "/path/to/bashscript.sh"");
    QString input = QString("Name");
    QString result = runCommand(cmd, input)
    

    Process Code:

    //takes 2 parameters, 
    //    cmd which is the code to be executed by the shell
    //    input which acts as the user input
    
    QString runCommand(QString cmd, QString input){
        QProcess *p = new QProcess(new QObject());
        p->setProcessChannelMode(QProcess::MergedChannels);   //no actual reason to do this
        p->start(cmd);
        if (p->waitForStarted()) {
            if (!p->waitForReadyRead()) {
                qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
            }
            if (!p->waitForFinished()) {
    
                //reads current stdout, this will show the input request from the bash script
                //e.g. please enter your name:
                qDebug() << p->readAll();  
    
                //here I write the input (the name) to the process, which is received by the script
                p->write(ps.toLatin1());
    
                //the script should then display a message i.e. ("success" o "failed")
                if (!p->waitForReadyRead()) {
                    qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
                }
                if (!p->waitForFinished()) {
                    qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
                }
            }
            QString s = QString(p->readAll() + p->readAllStandardOutput());
            return s;
        }
        else{
            qDebug() << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
        }
        p->waitForFinished();
        p->kill();
        return QString();
    }
    

    script.sh ( -rwxrwxr-x )

    #!/bin/bash
    #returns 
    #    "success" on non empty $n value
    #    "failed: on empty $n value
    #
    echo "enter your name:"
    read n
    if [[ ! -z $n ]];
    then
            echo "success"
            exit 0;
    else
            echo "failed"
            exit 1;
    fi
    

    UPDATE

    @KevinKrammer I modified the run command as you said, also using the QStringList with the args.

    Still does not get output, infact the waitForReadyRead() and waitForFinished() returns false instantly.

    Called with:

    QString r = runCommand(QString("text"));
    

    Process Code:

    QString runCommand(QString input){      
    
        QProcess *p = new QProcess(new QObject());    
        p->setProcessChannelMode(QProcess::MergedChannels);
    
        //script is the same script refered to earlier, and the `cd /home/dev` IS required
        p->start("sh", QStringList() << "-c" << "cd /home/dev" << "./script");
        ;
        if (p->waitForStarted()) {
            if (!p->waitForReadyRead(5000)) {
                qDebug() << "waitForReadyRead() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
            }
            qDebug() << p->readAll();
            p->write(input.toLatin1());
            if(!p->waitForFinished(5000)){
                qDebug() << "waitForFinished() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
            }
            QString s = QString(p->readAll() + p->readAllStandardOutput());
            return s;
        }
        else{
            qDebug() << "waitForStarted() [false] : CODE: " << QVariant(p->error()).toString() << " | ERROR STRING: " << p->errorString();
        }
        p->waitForFinished();
        p->kill();
        return QString();
    }
    

    Terminal Output of the Process:

    started
    readChannelFinished
    exit code =  "0"
    waitForReadyRead() [false] : CODE:  "5"  | ERROR STRING:  "Unknown error"
    ""
    waitForFinished() [false] : CODE:  "5"  | ERROR STRING:  "Unknown error"
    Press <RETURN> to close this window...
    

    Thoughts on this?

    UPDATE 2

    @Tarod Thank you for taking the time to make a solution.

    It works, however not completely is expected.

    I copied over your code, exactly.

    Made a few changes in the mReadyReadStandardOutput()

    See additional info below.

    The problem:

    After running the application (and script), I get a result -> AWESOME

    Everytime it is the incorrect result ie "failed". -> NOT AWESOME

    Terminal Output:

    void MyProcess::myReadyRead()
    void MyProcess::myReadyReadStandardOutput()
    "enter your name:n"
    ""
    void MyProcess::myReadyRead()
    void MyProcess::myReadyReadStandardOutput()
    "failedn"
    Press <RETURN> to close this window...
    

    script contents:

    #!/bin/bash
    echo "enter your name:"
    read n
    echo $n > "/tmp/log_test.txt"
    if [[ ! -z "$n" ]];
    then
            echo "success"
            exit 0;
    else
            echo "failed"
            exit 1;
    fi
    

    /tmp/log_test.txt output

    myname
    

    running this manually from console:

    dev@dev-W55xEU:~$ ls -la script 
    -rwxrwxr-x 1 dev dev 155 Jan 25 14:53 script*
    
    dev@dev-W55xEU:~$ ./script 
    enter your name:
    TEST_NAME
    success
    
    dev@dev-W55xEU:~$ cat /tmp/log_test.txt 
    TEST_NAME
    

    Full 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)
        QString s = this->readAllStandardOutput();
        qDebug() << s;
        if (s.contains("enter your name")) {
            this->write(QString("myname" + QString("n")).toLatin1());
            qDebug() << this->readAllStandardOutput();
        }
    }
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        MyProcess *myProcess = new MyProcess();
    
        QString program = "/home/dev/script";
    
        myProcess->start("/bin/sh", QStringList() << program);
    
        a.exec();
    }
    
    #include "main.moc"
    

    script issue? QProcess issue?


    Unfortunately I don't have all your code, so I made an example. I hope it helps you.

    If I compare my code to yours, I think the problem could be you are not calling readAllStandardOutput() after writing or maybe you are not calling exec() in your main.cpp.

    #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 to test the application:

    echo "enter your name:"
    read n
    if [ ! -z "$n" ];
    then
        echo "success"
        exit 0;
    else
        echo "failed"
        exit 1;
    fi
    
    链接地址: http://www.djcxy.com/p/97048.html

    上一篇: Bash Shell:语法有什么区别?

    下一篇: 在Qt控制台应用程序中读取和写入QProcess