我有2个bash脚本
问题:
创建QProcess
时,如果QProcess
已完成或暂停用户输入,我无法区分。
我希望有一些功能,例如QProcess::atEnd
如果脚本完成则返回true,但即使QProcess
挂起用户输入(来自脚本),它也返回true
更多信息:
需要用户输入的脚本:name-please.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"
使用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"
有哪些建议绕过这个问题?
答案 0 :(得分:1)
三件事。
根据QProcess::atEnd()
的文档,仅当进程未运行(QProcess::NotRunning
)时才会返回true。那么......当你致电atEnd()
时,确定这个过程是不是真的完成了?我在你发布的代码中没有看到它,所以我不知道。
每次有新数据时,您的myReadyReadStandardOutput()
信号都会覆盖m_Proc::_out
成员变量。根据您的系统(以及Qt)缓冲对标准输出的写入的方式,您可能会将部分行读入_out
。因此,_out.contains()
调用可能会返回false,因为您在行中有at is your
之类的内容,而不是完整的what is your name:
。
将成员字符串_input
写入进程的标准输入,然后立即尝试从标准输出中再次读取。这将很可能不会返回_out
中您尚未拥有的任何数据。当控制返回到主事件循环时,Qt只与底层设备实际进行实际I / O操作。来自QIODevice
的文档:
QIODevice的某些子类,,如QTcpSocket和QProcess ,是异步的。这意味着诸如write()或read()之类的I / O函数总是立即返回,而当控制返回到事件循环时,可能会发生与设备本身的通信。
我解决您问题的建议是修改myReadyReadStandardOutput
信号。对于异步设备(例如套接字和子进程),数据可能以任意大小的块到达。这是我上面提到的 2 点。处理此问题的常用方法是在信号顶部放置如下内容:
if (!canReadLine())
return;
如果没有完整的数据线,那么你就会退出信号并返回主事件循环。如果返回true,则可以执行以下操作:
_out = readLine();
/* Process an entire line, e.g., check if it matches the request for name */
因此,信号设计为仅在整行数据上运行。这对于面向线路的终端或网络协议非常有用。在这种情况下,您可以调用QString::contains()
方法来检查这是否是请求名称的行,如果是,请编写它。但是你必须返回到事件循环才能写入数据,所以你要在下一次调用信号时处理下一行(please to meet you
)。全线可用。