我用一个QProcess中打开/bin/sh
或/usr/bin/bash
并有可能写命令外壳和读取输出到我的程序。
尝试将结束文本控制信号发送到外壳中止壳的运行子进程时,会出现实际的问题。
我的尝试:
-i
nteractive模式启动set -m
命令启用作业控制$-
变量,它似乎是himBHs
ls
)\x04
(传输结束-键,Ctrl + d)的工作原理和杀死壳。我怎么能杀适当的运行过程中,无需再次打开的壳呢?
QProcess process;
process.start("/bin/sh", QStringList() << "-i");
process.write("set -m\necho $-\n"); // returns himBHs
process.waitForBytesWritten();
// start a running program here (E.g. tail -f logfile)
process.write("tail -f logfile\n");
process.write("\x03");
process.write("newcommand\n");
process.waitForBytesWritten();
运行在标准输出上输出的外壳内返回的第一个命令,但是我不接受任何发送ETX和下一个命令后了,虽然外壳仍在运行(process.state() == QProcess::Running
)
一个shell不会看到Ctrl-C
。它是由(伪)解释末端,并转换为SIGINT
,即然后加载。
在当地,在一个子shell,报告其PID启动程序,然后使用该PID直接杀死它。
#include <QtCore>
#include <signal.h>
#include <cstdio>
int getPID(const QByteArray &line) {
int pid = 0;
char c1, c2;
if (sscanf(line.data(), "@@@%d@@%c%c", &pid, &c1, &c2) == 3)
if (c1 == '@' && (c2 == '\r' || c2 == '\n')) return pid;
return 0;
}
int main(int argc, char *argv[]) {
auto input = QByteArray(
"echo _kill_me_now_ > log\n"
"/bin/sh -c 'echo @@@$$@@@>&2; exec tail -f log'\n"
"echo done\n"
"exit\n")
.split('\n');
// tail -f will block
QCoreApplication app(argc, argv);
QProcess process;
int pid = 0;
auto const writeInputLine = [&] {
if (input.isEmpty()) return;
auto const line = input.takeFirst();
puts(line.data());
fflush(stdout);
process.write(line);
process.write("\n");
};
process.setProcessChannelMode(QProcess::SeparateChannels);
QObject::connect(&process, &QProcess::stateChanged, [](auto state) {
auto static const meta = QMetaEnum::fromType<QProcess::ProcessState>();
fprintf(stderr, "State=%s\n", meta.key(state));
fflush(stderr);
if (state == QProcess::NotRunning) QCoreApplication::quit();
});
QObject::connect(&process, &QProcess::readyReadStandardError, [&] {
auto const data = process.readAllStandardError();
if (auto p = getPID(data)) pid = p; // we could suppress pid output here
fputs(data.data(), stdout);
fflush(stdout);
if (data.endsWith("$ ")) writeInputLine();
});
QObject::connect(&process, &QProcess::readyReadStandardOutput, [&] {
while (process.canReadLine()) {
auto const line = process.readLine();
fputs(line.data(), stdout);
if (line.startsWith("_kill_me_now_") && pid) {
kill(pid, SIGTERM);
pid = 0;
}
}
fflush(stdout);
});
process.start("/bin/sh", {"--noediting", "-i"});
return app.exec();
}
使用ssh,由于需要将信号转发到远程进程,并且因此需要遥控终端(ssh -t
)。为此,你将派遣一个Ctrl-C
,远程终端将重新解释为一个正确的信号。
你试过用信号和QProcess
插槽玩?下面是一个简单的例子:
test::test(QObject* p)
: QObject (p),
process{}
{
connect(&process, SIGNAL(finished(int, QProcess::ExitStatus) ),
this, SLOT(hFinish()) );
process.start("/bin/sh", QStringList() << "-i");
process.write("set -m\necho $-\n"); // returns himBHs
process.waitForBytesWritten();
// start a running program here (E.g. tail -f logfile)
process.write("tail -f logfile\n");
process.write("\x03");
process.write("newcommand\n");
process.waitForBytesWritten();
}
void test::hFinish()
{
this->process.kill();
}