C++ 使用QProcess将EndOfText(Ctrl-C)发送到交互式shell
我使用QProcess打开C++ 使用QProcess将EndOfText(Ctrl-C)发送到交互式shell,c++,bash,qt,shell,qprocess,C++,Bash,Qt,Shell,Qprocess,我使用QProcess打开/bin/sh或/usr/bin/bash,可以将命令写入shell并将输出读取到我的程序中 实际问题发生在尝试向shell发送文本结束控制信号以中止shell正在运行的子进程时 我尝试的是: shell将在-i交互激活模式下启动 我使用shell内置的set-m命令来启用作业控制 出于调试目的,我读取了$-变量,它似乎是himBHs 发送任意命令通常有效(例如ls) 发送\x04(传输结束,Ctrl+D)会起作用并杀死外壳 如何在不再次打开shell的情况下恰当地
/bin/sh
或/usr/bin/bash
,可以将命令写入shell并将输出读取到我的程序中
实际问题发生在尝试向shell发送文本结束控制信号以中止shell正在运行的子进程时
我尝试的是:
- shell将在
交互激活模式下启动-i
- 我使用shell内置的
命令来启用作业控制set-m
- 出于调试目的,我读取了
变量,它似乎是$-
himBHs
- 发送任意命令通常有效(例如
)ls
- 发送
(传输结束,Ctrl+D)会起作用并杀死外壳\x04
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();
QProcess过程;
process.start(“/bin/sh”,QStringList()shell永远不会看到Ctrl-C
。它由(伪)终端解释并转换为,然后对其执行操作
在本地,在报告其pid的子shell中启动程序,然后使用该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();
}
#包括
#包括
#包括
int getPID(常数QByteArray和line){
int-pid=0;
字符c1,c2;
如果(sscanf(line.data(),“@@@d@@@c%c”,&pid,&c1,&c2)==3)
如果(c1='@'&&(c2='\r'| c2='\n'))返回pid;
返回0;
}
int main(int argc,char*argv[]){
自动输入=QByteArray(
“echo\u kill\u me\u now\u>日志\n”
“/bin/sh-c'echo@$@@@@2;exec tail-f log'\n”
“回显完成\n”
“退出\n”)
.split('\n');
//tail-f将阻塞
QCore应用程序应用程序(argc、argv);
QProcess过程;
int-pid=0;
自动常量writeInputLine=[&]{
if(input.isEmpty())返回;
auto const line=input.takeFirst();
put(line.data());
fflush(stdout);
进程。写入(行);
进程。写入(“\n”);
};
process.setProcessChannelMode(QProcess::SeparateChannels);
QObject::connect(&process,&QProcess::stateChanged,[](自动状态){
自动静态常量meta=QMetaEnum::fromType();
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();
如果(auto p=getPID(data))pid=p;//我们可以在这里抑制pid输出
fputs(data.data(),stdout);
fflush(stdout);
如果(data.endsWith($)writeInputLine();
});
QObject::connect(&process,&QProcess::readyReadStandardOutput,[&]{
while(process.canReadLine()){
auto const line=process.readLine();
fputs(line.data(),stdout);
if(line.startsWith(“\u kill\u me\u now”&&pid){
kill(pid,SIGTERM);
pid=0;
}
}
fflush(stdout);
});
process.start(“/bin/sh”,{--noediting”,“-i”});
返回app.exec();
}
使用ssh,由于您需要将信号转发到远程进程,因此您需要一个远程控制终端(ssh-t
)。对于,您将发送一个Ctrl-C
,远程终端将重新解释为一个正确的信号