当您按下Ctrl+X,您的终端仿真器写入字节为0x18到伪终端对的主面。
接下来发生的情况取决于tty行规程(内核中位于主端(在仿真器的控制下)和从属端(在终端中运行的应用程序进行交互)之间的软件模块)的配置方式。
配置tty行规程的stty
命令是该命令。
当运行这样的愚蠢的应用程序时cat
,它不知道并且不关心其stdin是否为终端,该终端处于默认规范模式,其中tty行规程实现了粗线编辑器。
一些需要比粗线编辑器更多的交互式应用程序通常在启动时更改这些设置,并在离开时恢复它们。在它们的提示下,现代外壳就是此类应用程序的示例。他们实现了自己的更高级的行编辑器。
通常,当您输入命令行时,shell会将tty行规则设置为该模式,并且当您按Enter键以运行当前命令时,shell会恢复正常的tty模式(如发出提示之前的效果一样)。
如果运行stty -a
命令,您将看到哑应用程序正在使用的当前设置。你可能会看到icanon
,echo
和echoctl
被启用设置。
这意味着:
icanon
:启用了粗线编辑器。
echo
:键入(即终端仿真器写入到主侧)字符呼应背部(供终端仿真器读取提供)。
echoctl
:而不是被的回荡 ASIS,控制字符被呼应为^X
。
因此,假设您输入A B Backspace-aka-Ctrl+H/? C Ctrl+X Backspace Return。
您的终端仿真器将发送:AB\bC\x18\b\r
。线路规程将回声回:AB\b \bC^X\b \b\b \b\r\n
,和读取从从设备侧的输入的应用程序(/dev/pts/x
)的读出AC\n
。
该应用程序看到的全部是AC\n
,并且仅在您按下Enter该按钮时才对^X
那里的输出没有任何控制。
您会注意到,对于echo,第一个^H
(^?
带有某些终端,请参见erase
设置)导致\b \b
被发送回终端。这是将光标移回,用空格覆盖,再次移回光标的顺序,而第二个顺序^H
导致\b \b\b \b
擦除了这两个^
和X
字符。
的^X
(为0x18)本身正在翻译成^
与X
用于输出。像一样B
,它没有进入应用程序,因为我们使用Backspace删除了它。
\r
(aka ^M
)转换为\r\n
(^M^J
)进行回显,将\n
(^J
)转换为应用程序。
那么,对于那些愚蠢的应用程序,我们有哪些选择:
- 禁用
echo
(stty -echo
)。通过...不回声任何东西,有效地改变了控制字符的回声方式。并不是真正的解决方案。
- 禁用
echoctl
。这改变了控制字符(^H
,^M
...和行编辑器使用的所有其他字符)的回显方式。然后按原样回显它们。例如,ESC字符作为\e
(^[
/ 0x1b
)字节^G
发送\a
(终端将其识别为转义序列的开始),而您发送了(BEL,使您的终端发出蜂鸣声)...不是一种选择。
- 禁用粗线编辑器(
stty -icanon
)。并不是真正的选择,因为原始应用程序将变得不那么可用。
- 编辑内核代码以更改tty行规则的行为,以便发送控制字符的回声
\e[7m^X\e[m
而不是发送回声^X
(此处\e[7m
通常在大多数终端中启用反向视频)。
一种选择可能是使用像rlwrap
这样的包装器,这是一种肮脏的技巧,可以将奇特的行编辑器添加到愚蠢的应用程序中。实际上,该包装程序尝试read()
将终端设备中的simple替换为对readline行编辑器的调用(这确实会更改tty行规程的模式)。
更进一步,您甚至可以尝试像这样的解决方案,该解决方案^X
依赖于GNU屏幕的:exec
功能,劫持来自终端的所有输入以通过zsh的行编辑器(恰好在反向视频中突出显示s)。
现在,对于确实实现自己的行编辑器的应用程序,由他们来决定如何完成回显。bash
使用readline表示不支持自定义控制字符回显方式的内容。
对于zsh
,请参见:
info --index-search='highlighting, special characters' zsh
zsh
确实会默认突出显示不可打印的字符。您可以使用以下方法自定义突出显示:
zle_highlight=(special:fg=white,bg=red)
对于那些特殊字符用红色突出显示的白色。
但是,这些字符的文本表示不可自定义。
在UTF-8语言环境,为0x18将呈现为^X
,\u378
,\U7fffffff
(二未分配的Unicode代码点)为<0378>
,<7FFFFFFF>
,\u200b
(一个不真正打印Unicode字符)的<200B>
。
\x80
在iso8859-1语言环境中将被呈现为^�
...等。
bash
它正在readline
处理这些东西,而对于大多数其他人来说,它是tty驱动程序。