这是关于退格 ( \b
) 字符的行为。我有以下 C 程序:
int main() {
printf("Hello\b\b");
sleep(5);
printf("h\n");
return 0;
}
我的终端上的输出是
Helho
随着光标前进到下一行的第一个位置。
首先,整个内容仅在 5 秒睡眠后打印,因此我推断从内核到终端的输出是行缓冲的。所以现在,我的问题是:
- 由于
\b\b
回到两个空格,到 (second) 的位置l
,然后类似于如何l
替换为h
,o
应该已替换为\n
。为什么不是? - 如果我删除 line
printf("h\n");
,它会打印Hello
并返回两个字符,而不删除。我从其他答案中得到的这是因为非破坏性退格。为什么输入和输出的这种行为不同?也就是说,如果我在终端中输入一些东西(即使是同一个程序)并按 Backspace,它会删除最后一个字符,但不会删除输出。为什么?
如果有帮助,我正在使用 bash 的 xterm 终端上的 Ubuntu 系统上。
不,从您的程序到内核的输出是行缓冲的。
stdio
这是whenstdout
是终端的默认行为。添加调用setbuf(stdout, NULL)
以关闭stdout
. 见setbuf(3)
。因为换行符只是移动光标(并滚动屏幕),所以它不会打印为会在终端上占据字形位置的可见字符。如果我们假设它会取代字形,它会是什么样子?
好吧,当您键入时会发生什么取决于终端处于什么模式。粗略地说,它可以处于通常的“熟”模式,终端本身提供基本的行编辑(处理退格);或者在“原始”模式下,所有按键都转到应用程序,由应用程序决定如何处理它们,以及输出什么作为响应。熟模式通常伴随着“本地回显”,终端(用户本地)在输入字符时打印出字符。在原始模式下,应用程序通常负责回显键入的字符,以完全控制可见的内容。
有关终端模式的讨论,请参见例如这个问题: “原始”和“熟”设备驱动程序之间有什么区别?
如果您运行 eg
cat
,终端将处于熟模式(默认)并处理行编辑。例如,点击xBackspaceCtrl-D将导致cat
仅读取空输入,表示输入结束。您可以使用strace
. 但是,如果您改为运行交互式 Bash shell,它将自行处理退格,并输出它认为适合执行用户期望的操作,即擦除一个字符。strace -etrace=read,write -obash.trace bash
这是输入上述序列后的部分输出xBackspaceCtrl-D:首先, Bash
read
s 和write
sx
,将其输出到终端。然后读取退格符(八进制的字符代码 0177 或十进制的 127),并输出退格符(八进制 010,十进制 8 (*))将光标向后移动并输出清除行尾的控制序列,<ESC>[K
. 最后一个\4
是Ctrl-D
,Bash 使用它来退出程序。(* 在输入中,
Ctrl-H
将具有十进制字符代码 8。退格与此处相同或 127,再次取决于终端的设置方式。)相比之下,相同的实验
cat
只显示了一次读取零字节,即“文件结尾”条件。文件结束可能意味着连接的管道或套接字被关闭,文件的实际结束,或者Ctrl-D
在熟模式下从终端接收:特别是,
cat
看不到x
,也看不到退格,也看不到Ctrl-D
: 它们由终端处理。这可能是内核中的虚拟终端驱动程序;通过串行连接等的实际物理终端;或者像 xterm 这样的终端仿真器,可以在同一台机器上运行,也可以在 SSH 连接的远程端运行。这对用户空间软件无关紧要。代码(
\b
等\n
)移动光标,而不是文本。我想你会发现这种行为源于“过去的美好时光”,当时我们不得不操纵打印机上的光标以获得令人惊叹的效果,例如粗体字体和电传打字机、高尔夫球打印机等上的删除线。
\b
只需将插入点向后移动并允许您改写。在数字屏幕上,这会删除以前的内容,但在旧打印机上,您会得到覆盖字符。\n
将光标移动到新行,但将旧行上的文本留在后面。这将是一个 CRLF,它将光标放回行首并告诉打印机向上滚动一行。CR、LF 和 CRLF 代码再次与操纵旧设备以获得那些新奇效果的需要相关联。
.....并且没有任何方法可以从打印的页面中删除字符,您应该在发布打印之前得到它。
编辑
重新点 2。输入和输出做不同的事情,因为你告诉他们。
\b
相当于关闭 INSERT 的左箭头,而不是删除。\n
相当于向下箭头 (LF) 和 HOME (CR),而不是“输入”键击。首先,如果你想了解这些东西,你应该阅读
你问,
这里有一些琐事:在 Unix 的早期(1970 年代,甚至在 Linux 出现之前),退格1 并没有删除输入字符,用户讨厌它。你输入
beast
,按 Backspace 三次,你仍然会有一双邪恶的眼睛be|ast
盯着你(|
代表光标)。即使在您输入之后st
(因为您一直想说best
),屏幕仍然会显示best|t
,并且令人困惑。许多用户习惯于 Backspace Space Backspace 每个要删除的字符键入一次,以便使用空格替换/销毁坏字符;即,手动擦除它们。最终(1979 年或 1980 年代初),开发人员让步了,将其自动化:
其中“Ctrl-H”是退格的控制代码。
在某些情况下,您可以关闭此选项并通过键入
stty -echoe
(echoe
= “echo erase”,-
表示“不要这样做”) 来获取旧行为。____
1实际上,在早期,退格不是退格——但那是另一回事了。