简体   繁体   English

确定QProcess是已完成执行还是正在等待用户输入(或响应)

[英]Determine if QProcess has finished executing or is awaiting user input (or response)

I have 2 bash scripts 我有2个bash脚本

  1. One script not requiring user input, it displays info 一个脚本不需要用户输入,它显示信息
  2. The other requires some user input, and displays some info too 另一个需要一些用户输入,并且也显示一些信息

Problem: 问题:

When creating a QProcess , I am unable to differentiate if the QProcess is finished or is hanging for user input. 创建QProcess ,我无法区分QProcess是完成还是挂起供用户输入。

I was hoping for some function eg QProcess::atEnd that returns true if the script is finished, but it returns true even if the QProcess is hanging for user input (from script) 我希望有一些函数,例如QProcess::atEnd ,如果脚本完成则返回true,但是即使QProcess为用户输入而挂起(从脚本)也返回true。

More Info: 更多信息:

  • Script requiring user input : name-please.sh 需要用户输入的脚本: name-please.sh

  • Script not requiring input : hello.sh 脚本不需要输入: hello.sh

name-please.sh 名称-请

#!/bin/bash
echo "I am Mr Robot"
echo "what is your name:"

read n

if [[ ! -z "$n" ]];
then
        echo "please to meet you"
        exit 0;
else
        echo "ok, bye..."
        exit 1;
fi

hello.sh 你好

#!/bin/bash
echo "I am Mr Robot"

using mReadyReadStandardOutput() , I read the script output. 使用mReadyReadStandardOutput() ,我读取了脚本输出。 The issue exists around the fact that I need to read the output, determine if the output contains a line that requests user info (line from the script) and respond to that. 我需要阅读输出,确定输出是否包含要求用户信息的行(脚本中的行)并对此进行响应,因此存在这个问题。

see code with pointer to line 查看带有指向行的指针的代码

Code: 码:

 #include <QCoreApplication>
#include <QLoggingCategory>
#include <QTextStream>
#include <QProcess>
#include <QString>
#include <QVariant>
#include <QDebug>
#include <QObject>
#include <QEventLoop>

class m_Proc : public QProcess
{
    Q_OBJECT

public:
    int exitCode = -1;
    QString _out, _input;

    m_Proc(QString input = QString(), QObject *parent = 0);
    ~m_Proc() {}

public slots:
    void myReadyReadStandardOutput();
    void myFinished(int i);
};

m_Proc::m_Proc(QString input, QObject *parent)
{
    connect(this,SIGNAL(readyReadStandardOutput()),
            this,SLOT(myReadyReadStandardOutput()));
    connect(this, SIGNAL(finished(int)),
            this, SLOT(myFinished(int)));
}

void m_Proc::myReadyReadStandardOutput() {
    // Note we need to add \n (it's like pressing enter key)
    _out = this->readAllStandardOutput();
    if (!_input.isEmpty()) {

        /* 
         * check if line matches that of the script, 
         * where the user is required to enter their name
         */

        if (_out.contains("what is your name")) {         <<< ---- LINE WITH ISSUE
            this->write(QString(_input + QString("\n")).toLatin1());
            _out = this->readAllStandardOutput();
        }
    }
    else
        qDebug() << "Input Emptry (should not be reached!) !";
}

void m_Proc::myFinished(int i){
    exitCode = i;
    qDebug() << "exit code = " << QString::number(exitCode);
    qDebug() << _out;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    m_Proc *myProcess1 = new m_Proc(QString("text"));

    //    QString program = "/home/dev/script";

    myProcess1->start("/home/dev/script", QStringList());// << "one" << "two");

    //    myProcess1->start("/bin/sh", QStringList() << "-c" << "ls" << "-la");


    a.exec();
}

#include "main.moc"

Any advice to bypass this issue? 有什么建议可以绕过这个问题?

Three things. 三件事。

  1. According to the documentation for QProcess::atEnd() , this returns true only if the process is not running ( QProcess::NotRunning ). 根据QProcess::atEnd()的文档,仅当进程未运行时,此返回true( QProcess::NotRunning )。 So...are you sure the process isn't truly done when you call atEnd() ? 那么...您确定在调用atEnd()时确实没有完成该过程吗? I don't see it anywhere in the code you've posted, so I can't tell. 我在您发布的代码中的任何地方都看不到它,所以我不知道。

  2. Your myReadyReadStandardOutput() signal is overwriting the m_Proc::_out member variable each time new data is available. 每当有新数据可用时,您的myReadyReadStandardOutput()信号就会覆盖m_Proc::_out成员变量。 Depending on how writes to standard output are buffered on your system (and by Qt), you may be reading partial lines into _out . 根据对系统(以及Qt)对标准输出的写入进行缓冲的方式,您可能会将部分行读入_out Thus the _out.contains() call may return false, because you've got something like at is your in the line, rather than the full what is your name: . 因此_out.contains()调用可能返回false,因为at is your在一行中有at is your ,而不是完整what is your name:

  3. You write the member string _input to the process's standard input, and then immediately try to read again from the standard output. 您将成员字符串_input写入流程的标准输入,然后立即尝试再次从标准输出中读取。 This will most likely not return any data that you didn't already have in _out . 很可能不会返回 _out 没有的任何数据 Qt only really does actual I/O with the underlying device when control returns to the main event loop. 当控制返回到主事件循环时,Qt才真正对底层设备执行实际的I / O。 From the documentation for QIODevice : QIODevice的文档中:

Certain subclasses of QIODevice, such as QTcpSocket and QProcess , are asynchronous. QIODevice的某些子类( 例如QTcpSocket和QProcess )是异步的。 This means that I/O functions such as write() or read() always return immediately, while communication with the device itself may happen when control goes back to the event loop. 这意味着诸如write()或read()之类的I / O函数总是立即返回,而当控制权返回事件循环时,与设备本身的通信可能会发生。

My suggestion for solving your issue would be to modify the myReadyReadStandardOutput signal. 对于解决您的问题,我的建议是修改myReadyReadStandardOutput信号。 For asynchronous devices (such as sockets and sub-processes), data may arrive in arbitrary-sized chunks. 对于异步设备(例如套接字和子进程),数据可能以任意大小的块到达。 This is point 2 I made above. 这是第2点我上面制备。 The usual method for dealing with this is to put something like the following at the top of the signal: 解决此问题的常用方法是在信号顶部放置以下内容:

if (!canReadLine())
    return;

So you bail out of the signal and return to the main event loop if a full line of data is not available. 因此,如果没有完整的数据行,您将摆脱困境并返回主事件循环。 If that returns true, you can do something like: 如果返回true,则可以执行以下操作:

_out = readLine();
/* Process an entire line, e.g., check if it matches the request for name */

So the signal is designed to operate only on full lines of data. 因此,信号被设计为仅在整行数据上运行。 This is useful for terminals or network protocols that are line-oriented. 这对于面向行的终端或网络协议很有用。 In this case, you can call the QString::contains() method to check if this is the line requesting a name, and, if so, write it. 在这种情况下,您可以调用QString::contains()方法来检查这是否是请求名称的行,如果是,请编写该行。 But you must then return to the event loop in order for the data to be written, so you'd process the next line ( please to meet you ) in the next call to the signal in which a full line is available. 但是您必须返回到事件循环才能写入数据,因此您将在下一个对信号进行调用的行中处理下一行( please to meet you )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM