我有两个bash脚本
- 一个不需要用户输入的脚本,它显示信息
- 另一个需要一些用户输入,并显示一些信息
问题:
创建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"
有什么绕过这个问题的建议吗?
三件事。
-
根据
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,是异步的。这意味着写()或读()等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
)。