[英]Determine if QProcess has finished executing or is awaiting user input (or response)
I have 2 bash scripts 我有2个bash脚本
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. 三件事。
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. 我在您发布的代码中的任何地方都看不到它,所以我不知道。
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:
。
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.