屏幕/dev/pts/虚拟机的 stty 设置从来没有正确

屏幕/dev/pts/虚拟机的 stty 设置从来没有正确

设置虚拟机(使用 linux+kvm+qemu)为终端提供串行端口,该端口可通过伪终端(一些随机终端)使用/dev/pts/<number>

我使用 screen 作为与 交互的方式/dev/pts/<number>,因为事实证明它比 cat /dev/pts/<number> & cat > /dev/pts/<number>不能正确处理转义符(如ctrl-c)或多次回显输入的方式更好。

stty --all这个问题的问题和核心是,通过shell 内部查询的“tty/pts”的设置screen /dev/pts/<number>没有关于尺寸(colsrows)的正确设置,这实际上会因内部不正确的换行等而导致头痛。 VM 的外壳。

由于这里有超过 1 台机器和终端/tty/pts 在运行,我没有足够的经验来了解如何设置正确的设置。

如何screen /dev/pts/<number>让 shell 知道正确的stty设置?

** 更新 **

stty --all虚拟机外壳内的输出是。

root@mail:~# stty --all
speed 115200 baud; rows 24; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon ixoff
-iuclc -ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke -flusho -extproc

stty --all主机系统 shell 中的输出是

speed 38400 baud; rows 39; columns 147; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff -iuclc -ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

答案1

如果您将交互式 shell 初始化设置为运行resize,它会询问终端有多大,并执行相同的系统调用stty

该块位于 a 的末尾.bashrc会工作:

if [ -t 0 ] && [ -t 1 ] && [[ $TERM == screen* ]] && [ -f /usr/bin/resize ];然后
  调整大小 >/dev/null
  # stty-a

它检查标准输入/输出是否是终端(即会话是交互式的),如果TERM设置为其中之一screen口味,以及是否resize已安装。

重定向输出resize不会干扰它向终端发送转义序列并获得回复,因为它打开为此,它有自己的流到 tty。

进一步阅读:

答案2

太长;博士;为了使串行连接后面的内部终端接收终端仿真器的尺寸设置,请将其放入您的./bashrc

set_terminal_dimension() (
  old="$(stty -g)"
  stty raw -echo min 0 time 1
  printf '\033[18t' >/dev/tty
  IFS=';t' read -r _ rows cols _ </dev/tty
  stty "$old";
  stty cols "$cols" rows "$rows"
)
PROMPT_COMMAND='set_terminal_dimension'

背景详情

连接到linux系统的其中一个serial connection(即/dev/ttyS0)提供了输入和输出的字节数据流。然而,它不提供 IPC(进程间通信方法,如信号)。因此不存在信号绞车这将:

当进程的控制终端改变其大小(窗口改变)时,SIGWINCH 信号被发送到进程。

当然,显示从串行连接接收到的输出的不同计算机也不能发出终端设置(例如通过stty),因为它不是同一台机器。

两台机器之间:a) TARGET-Sys 在串行连接后面提供 shell,b) CONNECTING-Sys 通过串行连接读写 TARGET 系统,问题是这样的:

系统“a) TARGET”正在运行 shell,需要设置有关连接的正确信息(即可以通过命令行实用程序设置stty)。它无法知道屏幕上可以显示多少个字符的尺寸(cols并且rows,只有“b)连接”系统,更准确地说是其终端仿真器应用程序知道它)。

系统 a) 和 b) 通过两个字节流 i) 输入和 ii) 输出连接,需要通过同一流交换信息,主要见于发送到“a) 目标的键盘输入和从“a) 目标接收的输出colsrows“ 系统。显然,这种信息交换可能与已发送的正常字节冲突,这就是为什么可以使用一种协议,其中尝试通过使用转义字节序列来专门标记信息。正如本文中所阐述的回答串行通信与 ssh 连接(也连接两个系统)相反,不是使用 NAWS 等特殊协议进行设置(请参阅回答“终端长度和宽度如何通过 SSH 和 telnet 转发?”)。

resize这里的另一个答案建议使用通常由发行版打包的现成程序。这个答案建议更多的轻量级选择,这可能更符合“简洁减少包依赖性“-人们对许多通过 GUI 使用串行通信的系统(例如Xorg服务器)所期望的态度

在 Archlinux Wiki 上的“使用串行控制台”中“疑难解答部分”另外要提一下resize许多发行版的软件包中包含的命令xterm。由于使用串行连接通常与通过串行连接连接的系统上不需要图形输出/GUI 相一致,因此该xterm解决方案可能是一个相当大的解决方案(给 Xorg 服务器......作为包依赖项)。

因此,关于终端的尺寸,此处有说明

  1. 如果您不想安装 xterm,可以通过 shell 函数完成相同的工作。将以下函数放入 zshrc 中,并在调整终端模拟器窗口大小后不带参数调用它:

此处概述的解决方案还进一步说明了终端如何请求并接收来自另一端终端仿真器的响应。一个更轻量级的解决方案可能类似于这个 bash 脚本/bin/sbin/resize.sh

#!/bin/bash

## store tty settings before
old="$(stty -g)"

## briefly disable any stty setting, like echo or line discipline
## because for a brief moment a escape sequence is send (to be received
## by the receiver (a terminal emulator program)
## a) raw => no line discipline
## b) -echo => disable repeating and display stuff 
## c) min 0 time 1 => return a read with after 1 tenth of a sec and no minimum bytes 
stty raw -echo min 0 time 1

## send the request an escape sequence for the outer terminal emulator
printf '\033[18t' >/dev/tty

## use read shell builtin to read the return into the variables rows, cols
## (IFS is used in combination with a "_" (as "garbage variable") to 
##  get rid of not neede part of response)
IFS=';t' read -r _ rows cols _ </dev/tty

## (previous settings are restore, ie. the "raw" and "-echo" is undone)
stty "$old";

## finally the received info ( the info provided via the same stream
## of bits as bytes as also actually incoming the bytes generated by the 
## keyboard ) and which was read into the variables was set before
stty cols "$cols" rows "$rows"

相关内容