Home Articles

在Qt控制台应用程序中读写QProcess

Asked
Viewed 667 times
1

注意:这似乎是一个特定的问题,但希望它可以编辑为所有相关的问题

我需要与QProcess对象进行交互 .

The Problem:

在调用 QProcess:write(input) 后,我没有从 QProcess 获得任何输出

More Info:

通过doc pages让我创建了一个示例如下:

我有一个脚本请求用户输入,最后根据用户输入显示和适当的消息 .

Testing:

在我的脚本中添加“日志”功能进行测试后,会发生以下情况:

  • 脚本执行

  • 脚本请求用户输入(由'first' qDebug() << p->readAll() 确认)

  • 脚本接受来自 QProcess 的输入(由脚本'log output'确认)

在此之后,没有收到输出 . 以下两个调试语句都会触发(即每个等待30秒)

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

其中 s 是一个空字符串 .

问题是 s 应包含"success"或"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我按照你的说法修改了run命令,也使用带有args的QStringList .

仍然没有得到输出,实际上是 waitForReadyRead()waitForFinished() returns false .

叫:

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

流程代码:

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

过程的终端输出:

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

对此的想法?

UPDATE 2

@Tarod感谢您抽出宝贵时间来解决问题 .

它起作用,但并不完全是预期的 .

我完全复制了你的代码 .

mReadyReadStandardOutput() 做了一些改动

请参阅下面的其他信息

The problem:

运行应用程序(和脚本)后,我得到一个结果 - >真棒

每次都是错误的结果,即“失败” . - >不太棒

Terminal Output:

void MyProcess::myReadyRead()
void MyProcess::myReadyReadStandardOutput()
"enter your name:\n"
""
void MyProcess::myReadyRead()
void MyProcess::myReadyReadStandardOutput()
"failed\n"
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

完整代码:

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

脚本问题? QProcess问题?

1 Answer

  • 2

    不幸的是我没有你所有的代码,所以我做了一个例子 . 我希望它对你有所帮助 .

    如果我将我的代码与你的代码进行比较,我认为问题可能是你在写完之后没有调用 readAllStandardOutput() 或者你在main.cpp中没有调用 exec() .

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

    用于测试应用程序的脚本:

    echo "enter your name:"
    read n
    if [ ! -z "$n" ];
    then
        echo "success"
        exit 0;
    else
        echo "failed"
        exit 1;
    fi
    

Related