我正在编写一个程序来创建pty,然后派生并执行一个pty的从属端作为ssh
的stdin
命令。完整的源代码在这里。
using namespace std;
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = posix_openpt(O_RDWR);
grantpt(fd);
unlockpt(fd);
pid_t pid = fork();
if (pid == 0) { //slave
freopen(ptsname(fd), "r", stdin);
execlp("ssh", "ssh", "[email protected]", NULL);
} else { //master
FILE *f = fdopen(fd, "w");
string buf;
while (true) {
getline(cin, buf);
if (!cin) {
break;
}
fprintf(f, "%s\n", buf.c_str());
}
}
}
执行此程序并仅输入
echo hello
(和换行符)后,child命令在其自身输出之前重新发送我的输入,从而复制了我的输入行:~ $ echo hello
echo hello #duplication
hello
~ $
我认为这是由于pty的行为几乎与普通终端相同。如果我添加
freopen("log.txt", "w", stdout);"
并输入相同的命令,我将得到echo hello #This is printed because I typed it.
log.txt
的内容是这样的:~ $ echo hello #I think this is printed because a pty simulates input.
hello
~ $
如何避免重复?
可以实现吗?
我知道它可以实现,但是不知道如何实现。实际上,
rlwrap
命令的行为与我的程序相同,不同之处在于它没有任何重复:~/somedir $ rlwrap ssh [email protected]
~ $ echo hello
hello
~ $
我正在阅读
rlwrap
的源代码,但尚未理解其实现。补充
如this question中的建议(对我来说,不是答案,但OP很有帮助。),取消设置
ECHO
终端标志将禁用双重回显。就我而言,将此片段添加到从属块可以解决此问题。termios terminal_attribute;
int fd_slave = fileno(fopen(ptsname(fd_master), "r"));
tcgetattr(fd_slave, &terminal_attribute);
terminal_attribute.c_lflag &= ~ECHO;
tcsetattr(fd_slave, TCSANOW, &terminal_attribute);
应当注意,这不是
rlwrap
所做的。据我测试,rlwrap <command>
从不重复任何<command>
的输入行。但是,我的程序为<command>
重复了两次。例如,~ $ echo hello
hello #no duplication
~ $ /usr/bin/wolfram
Mathematica 12.0.1 Kernel for Linux ARM (32-bit)
Copyright 1988-2019 Wolfram Research, Inc.
In[1]:= 3 + 4
3 + 4 #duplication (my program makes this while `rlwrap` doesn't)
Out[1]= 7
In[2]:=
这是因为
<command>
(当我远程运行ssh
时为wolfram
)重新启用了回显吗?无论如何,我应该继续阅读rlwrap
的源代码。 最佳答案
正如您已经观察到的那样,在子进程调用exec()
之后,从属端的终端标志不再受您的控制,并且该子进程可能(并且经常会)重新启用echo。这意味着在调用exec
之前更改子级中的终端标志没有太大用处。
rlwrap和rlfe都以自己(不同)的方式解决了这个问题:
rlfe
保留输入的行,但是在显示子项之前从 child 的输出中输出removes the echo'ed input rlwrap
removes the entered line 并将其替换为echo 无论使用哪种方法,都必须知道您的输入是回显还是回显(对于
rlfe
而言)。至少,rlwrap
可以通过不关闭父进程中pty的从属端,然后查看其终端设置(在本例中为rlwrap
中的ECHO
位)来知道从属是否回显,从而做到这一点。当然,所有这些都非常麻烦。
c_lflag
方法可能更容易,因为它不需要使用rlfe
库,并且您可以使用刚刚发送的输入来简单地对接收到的输出进行readline
(这只会在strcmp()
命令禁用的可能性很小的情况下出错)在其输入上回显)关于c++ - 在pty下运行命令时出现双重回声,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59007528/