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



我有两个bash脚本

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

问题:

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

我希望有一些函数,例如QProcess::atEnd,如果脚本完成,它会返回true,但即使QProcess挂起等待用户输入(来自脚本),它也会返回true

更多信息:

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

  • 不需要输入的脚本:hello.sh

请命名。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

你好.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)时,此值才会返回true。那么……当您调用atEnd()时,您是否确定流程没有真正完成?我在你发布的代码中看不到它,所以我说不出来。

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

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

QIODevice的某些子类,如QTcpSocket和QProcess,是异步的。这意味着写()或读()等I/O函数总是立即返回,而当控制返回到事件循环时,可能会与设备本身进行通信。

我对解决您的问题的建议是修改myReadyReadStandardOutput信号。对于异步设备(如套接字和子进程),数据可能以任意大小的块到达。这是我在上面提出的要点。处理这种情况的常用方法是在信号的顶部放置以下内容:

if (!canReadLine())
return;

因此,如果没有完整的数据行,您可以退出信号并返回到主事件循环。如果这是真的,你可以做一些类似的事情:

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

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

最新更新