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

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

我有 2 bash 个脚本

  1. 一个不需要用户输入的脚本,它显示信息
  2. 另一个需要一些用户输入,也显示一些信息

问题:

创建 QProcess 时,我无法区分 QProcess 是已完成还是挂起以等待用户输入。

我希望有一些功能,例如QProcess::atEnd 如果脚本完成,returns 为真,但即使 QProcess 挂起以等待用户输入(来自脚本),它 returns 也为真

更多信息:

姓名-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"

使用 mReadyReadStandardOutput(),我阅读了脚本输出。问题存在于我需要读取输出、确定输出是否包含请求用户信息的行(脚本中的行)并对此做出响应这一事实。

查看带有指向行的指针的代码

代码:

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

有什么绕过这个问题的建议吗?

三件事。

  1. 根据 QProcess::atEnd() 的文档,仅当进程不是 运行 (QProcess::NotRunning) 时,此 return 才为真。那么...您 确定 当您调用 atEnd() 时,流程并未真正完成吗?我在您发布的代码中没有看到它,所以我无法判断。

  2. 每次有新数据可用时,您的 myReadyReadStandardOutput() 信号都会覆盖 m_Proc::_out 成员变量。根据系统(以及 Qt)缓冲标准输出的写入方式,您可能会将部分行读入 _out。因此 _out.contains() 调用可能 return 错误,因为你在行中有类似 at is your 的内容,而不是完整的 what is your name:.

  3. 您将成员字符串_input写入进程的标准输入,然后立即尝试从标准输出再次读取。这将 很可能不会 return 您在 _out 中还没有 的任何数据。当控制 return 到主事件循环时,Qt 只对底层设备进行实际的 I/O 操作。来自 QIODevice 的文档:

Certain subclasses of QIODevice, such as QTcpSocket and QProcess, are asynchronous. 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.

我对解决您的问题的建议是修改 myReadyReadStandardOutput 信号。对于异步设备(例如套接字和 sub-processes),数据可能以 arbitrary-sized 块的形式到达。这是我上面做的2点。通常处理这个问题的方法是在信号的顶部放置如下内容:

if (!canReadLine())
    return;

因此,如果整行数据不可用,则退出信号并 return 进入主事件循环。如果 return 为真,您可以执行以下操作:

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

因此信号被设计为仅对整行数据进行操作。这对于 line-oriented 的终端或网络协议很有用。在这种情况下,您可以调用 QString::contains() 方法来检查这是否是请求名称的行,如果是,则写入它。但是您必须然后 return 到事件循环 才能写入数据,因此您将在下一行处理下一行 (please to meet you)调用其中有完整行的信号。