当您在 Linux 上运行 cal 时,当月的输出将反转视频突出显示当天。当我将该输出发送到 hexdump -c 时,我得到了一些有趣的结果:
0000000 N o v e m b e r 2 0 1 6
0000010 \n S u M o T u
0000020 W e T h F r S a \n
0000030 1 2 _ \b _ \b 3
0000040 4 5 \n 6 7
0000050 8 9 1 0 1 1 1 2 \n
0000060 1 3 1 4 1 5 1 6 1 7 1
0000070 8 1 9 \n 2 0 2 1 2 2
0000080 2 3 2 4 2 5 2 6 \n 2 7
0000090 2 8 2 9 3 0
00000a0 \n
00000b0 \n
00000bc
正如您所看到的,在今天突出显示的“3”之前打印了一个不可见的序列 _\b _\b。 _ 是下划线(ASCII 十六进制中的 5F),\b 是 Ctrl-H 或 ASCII 十六进制中的 08。这是什么?我知道有很多晦涩的终端代码,但我希望它使用更标准的东西,比如 \e[7m.更奇怪的是,我无法通过使用标准 printf 函数(如以下命令之一)打印出相同的字符来重现 cal 的相同行为:
/usr/bin/printf "1 2 _\b _\b3 4 5\n"
/usr/bin/printf "1 2 _^H _^H3 4 5\n"
其中 ^H 是通过按 Ctrl-V Ctrl-H 生成的。但它们都不能产生与 cal 相同的逆视频输出。我什至尝试编写一个小 C 程序来做到这一点。我也尝试过使用 echo -e 。有趣的是,虽然它不会反转终端中的视频,但如果我通过 less -R 传输输出,它会将其颜色更改为黄色并为其添加下划线。在其他终端上我尝试过它只是强调它。这看起来几乎有点过分,但如果我使用 _ 以外的字符,它就不起作用,这让我认为 _\b 是单个代码序列。那么该角色的视频如何反转呢?
对此有何见解?
手册页说 cal 的输出应该是与原始 Unix cal 命令有点兼容的版本。所以我只能假设这是一些古老的代码。
答案1
这几乎看起来有点过分了
正是如此。正如所讨论的为什么 80 列的控制台上有 11 个制表符?,当谈到 Unix 终端时,它有助于思考机械打字机的操作。在这种情况下,字符之前的序列_
BS(退格字符)是一种约定,用于指示该字符的下划线,因为在某些终端上,这就是文本下划线的方式。另一种控制序列是_
字符后的 BS。当然,在最初的终端上,什么超出什么并不重要。在现代视频终端上,最后写入的字符“获胜”,从而擦除之前的数据。因此,_
BS <字符>顺序优先。
FreeBSD ncal
,也就是这个程序,在突出显示方面有两种操作模式。
- 如果其输出是终端,它会在 termcap 数据库中查找当前终端类型的
so
和se
序列,并在突出显示的文本的两侧发出这些序列。 (实际上,执行此操作的代码中有一个错误,与堆栈上的缓冲区超出范围及其内容稍后使用有关,似乎没有人发现这一点。) - 如果它的输出不是终端,它会发出文本,其中每个要突出显示的字符前面都有
_
BS 序列。
你不能通过向终端发出 BS 序列来复制这一点_
,除非(当然)你的终端是这样强调内容的终端之一。终端模拟器不是这种情况,而且几乎可以肯定,您在这里使用的任何终端或终端模拟器都不是这种情况。
但是,您可以筛选通过程序使用此约定的文本,ul
该程序识别此约定以及其他几个类似打字机的约定,并将它们转换为终端实际的控制序列,并在 termcap 数据库中查找它们。您也可以printf
通过过滤命令的输出ul
。
在其他终端上我尝试过它只是强调它。
ncal
具有讽刺意味的是,通过程序过滤非终端模式输出ul
实际上比让ncal
编写终端控制序列本身稍好一些。而ncal
使用终端的脱颖而出模式,ul
将尝试使用终端的实际强调转换 BS 序列时的模式(如果有)_
。正如 termcap 手册所解释的,突出模式可以是任何适合终端的模式(包括粗体、反向视频或颜色),并且不一定是下划线。在您的一个终端上,它显然是下划线和颜色变化的组合。
此外,ul
还可以处理没有下划线开始/结束序列但有下划线最后一个字符序列的终端。具有讽刺意味的是,ul
如果您的终端能够应对真的是_
一个在每个字符后面加上 BS 来强调的,而ncal
无法应对。
当然,ul
没有ncal
缓冲区处理错误。 ☺
如果我将输出通过管道传输到
less -R
,它会将其颜色更改为黄色并为其添加下划线。
正如您所发现的,该less
程序理解_
BS 序列并按照ul
程序的方式处理它们。并不完全一样。 ul
可以处理涉及多个 BS 字符的序列_
,也可以处理类似的粗体字符序列。 less
不能。对比一下您从这两者中看到的情况:
/usr/bin/printf "1 2 ______\b\b\b\b\b\b 3 _\b4。\b\b\b45 6\n" |乌尔
/usr/bin/printf "1 2 ______\b\b\b\b\b\b 3 _\b4。\b\b\b45 6\n" |较少的
回到过去的美好时光
可悲的是,这些仍然是“美好的旧时光”。不要让人们欺骗您,让您相信现在很少使用此功能。
它不在手册中,但源代码指出ul
它正在尝试实现 Teletype Model 37 的控制序列处理,因为“这就是输出nroff
”。原始 Unix 程序的 GNU 替代品nroff
是在终端获得颜色、粗体和斜体等奇特功能很久之后编写的,能够生成ECMA-48颜色、粗体和斜体的控制序列。事实上确实如此在正常情况下。
nroff
及其 GNU 替代品用于格式化手册页以在终端上显示。可悲且讽刺的是,从它编写大约 10 年后开始,人们开始对 GNU 工具进行阻碍,以便它生成 1968 年的旧 Teletype Model 37 序列,而不是 1976 年的“新”ECMA-48 控制序列(原文如此!)。他们使用修改其默认行为的选项进行man
调用groff
,并添加强制额外 ditroff 输出的未记录文件。
每次您在终端上阅读手册页时,手册系统都会运行groff
,该系统会尽职尽责地将手册源文本转换为使用这些旧的 Teletype Model 37 控制序列的输出字符流,这些控制序列less
或more
正在转换为终端的控制序列。
进一步阅读
答案2
Ctrl-H
是退格键,它将光标向左移动一步。在过去的好日子里,发送下划线、退格键和其他一些字符是在硬拷贝(“纸质”)终端上给某些内容加下划线的方法。这用于在 的输出中突出显示当天cal
。
我的cal
程序在运行时konsole
不会输出此序列。如果我运行script -c cal
并检查生成的typescript
文件,我可以看到 cal 程序使用转义序列<esc>[7m
切换到反转模式视频。