AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 414159
Accepted
forumulator
forumulator
Asked: 2018-01-02 09:43:51 +0800 CST2018-01-02 09:43:51 +0800 CST 2018-01-02 09:43:51 +0800 CST

终端上退格键的行为

  • 772

这是关于退格 ( \b) 字符的行为。我有以下 C 程序:

int main() {
    printf("Hello\b\b");
    sleep(5);
    printf("h\n");
    return 0;
}

我的终端上的输出是

Helho

随着光标前进到下一行的第一个位置。

首先,整个内容仅在 5 秒睡眠后打印,因此我推断从内核到终端的输出是行缓冲的。所以现在,我的问题是:

  1. 由于\b\b回到两个空格,到 (second) 的位置l,然后类似于如何l替换为h,o应该已替换为\n。为什么不是?
  2. 如果我删除 line printf("h\n");,它会打印Hello并返回两个字符,而不删除。我从其他答案中得到的这是因为非破坏性退格。为什么输入和输出的这种行为不同?也就是说,如果我在终端中输入一些东西(即使是同一个程序)并按 Backspace,它会删除最后一个字符,但不会删除输出。为什么?

如果有帮助,我正在使用 bash 的 xterm 终端上的 Ubuntu 系统上。

terminal tty
  • 3 3 个回答
  • 7199 Views

3 个回答

  • Voted
  1. Best Answer
    ilkkachu
    2018-01-02T10:59:11+08:002018-01-02T10:59:11+08:00

    首先,整个内容仅在 5 秒睡眠后打印,因此我推断从内核到终端的输出是行缓冲的。

    不,从您的程序到内核的输出是行缓冲的。stdio这是whenstdout是终端的默认行为。添加调用setbuf(stdout, NULL)以关闭stdout. 见setbuf(3)。

    1. 由于\b\b回到两个空格,到lthen 的位置类似于如何l被替换h,o应该已经被替换\n。为什么不是?

    因为换行符只是移动光标(并滚动屏幕),所以它不会打印为会在终端上占据字形位置的可见字符。如果我们假设它会取代字形,它会是什么样子?

    1. 如果我在同一个程序中输入一些内容,然后按 Backspace,它会删除最后一个字符,但不会删除输出。为什么?

    好吧,当您键入时会发生什么取决于终端处于什么模式。粗略地说,它可以处于通常的“熟”模式,终端本身提供基本的行编辑(处理退格);或者在“原始”模式下,所有按键都转到应用程序,由应用程序决定如何处理它们,以及输出什么作为响应。熟模式通常伴随着“本地回显”,终端(用户本地)在输入字符时打印出字符。在原始模式下,应用程序通常负责回显键入的字符,以完全控制可见的内容。

    有关终端模式的讨论,请参见例如这个问题: “原始”和“熟”设备驱动程序之间有什么区别?

    如果您运行 eg cat,终端将处于熟模式(默认)并处理行编辑。例如,点击xBackspaceCtrl-D将导致cat仅读取空输入,表示输入结束。您可以使用strace. 但是,如果您改为运行交互式 Bash shell,它将自行处理退格,并输出它认为适合执行用户期望的操作,即擦除一个字符。


    strace -etrace=read,write -obash.trace bash这是输入上述序列后的部分输出xBackspaceCtrl-D:

    read(0, "x", 1)                         = 1
    write(2, "x", 1)                        = 1
    read(0, "\177", 1)                      = 1
    write(2, "\10\33[K", 4)                 = 4
    read(0, "\4", 1)                        = 1
    

    首先, Bash reads 和writes x,将其输出到终端。然后读取退格符(八进制的字符代码 0177 或十进制的 127),并输出退格符(八进制 010,十进制 8 (*))将光标向后移动并输出清除行尾的控制序列,<ESC>[K. 最后一个\4是Ctrl-D,Bash 使用它来退出程序。

    (* 在输入中,Ctrl-H将具有十进制字符代码 8。退格与此处相同或 127,再次取决于终端的设置方式。)

    相比之下,相同的实验cat只显示了一次读取零字节,即“文件结尾”条件。文件结束可能意味着连接的管道或套接字被关闭,文件的实际结束,或者Ctrl-D在熟模式下从终端接收:

    read(0, "", 131072)                     = 0
    

    特别是,cat看不到x,也看不到退格,也看不到Ctrl-D: 它们由终端处理。这可能是内核中的虚拟终端驱动程序;通过串行连接等的实际物理终端;或者像 xterm 这样的终端仿真器,可以在同一台机器上运行,也可以在 SSH 连接的远程端运行。这对用户空间软件无关紧要。

    • 8
  2. bu5hman
    2018-01-02T10:14:32+08:002018-01-02T10:14:32+08:00

    代码(\b等\n)移动光标,而不是文本。

    我想你会发现这种行为源于“过去的美好时光”,当时我们不得不操纵打印机上的光标以获得令人惊叹的效果,例如粗体字体和电传打字机、高尔夫球打印机等上的删除线。

    \b只需将插入点向后移动并允许您改写。在数字屏幕上,这会删除以前的内容,但在旧打印机上,您会得到覆盖字符。

    \n将光标移动到新行,但将旧行上的文本留在后面。这将是一个 CRLF,它将光标放回行首并告诉打印机向上滚动一行。

    CR、LF 和 CRLF 代码再次与操纵旧设备以获得那些新奇效果的需要相关联。

    .....并且没有任何方法可以从打印的页面中删除字符,您应该在发布打印之前得到它。

    编辑

    重新点 2。输入和输出做不同的事情,因为你告诉他们。

    \b相当于关闭 INSERT 的左箭头,而不是删除。

    \n相当于向下箭头 (LF) 和 HOME (CR),而不是“输入”键击。

    • 4
  3. G-Man Says 'Reinstate Monica'
    2018-01-02T22:40:11+08:002018-01-02T22:40:11+08:00

    首先,如果你想了解这些东西,你应该阅读

    • “终端”、“外壳”、“tty”和“控制台”之间的确切区别是什么?
    • TTY 揭开神秘面纱

    你问,

    ……如果我输入一些东西……,然后按 Backspace,它会删除最后一个字符,但不会删除输出。为什么?

    这里有一些琐事:在 Unix 的早期(1970 年代,甚至在 Linux 出现之前),退格1 并没有删除输入字符,用户讨厌它。你输入beast,按 Backspace 三次,你仍然会有一双邪恶的眼睛be|ast盯着你(|代表光标)。即使在您输入之后st(因为您一直想说best),屏幕仍然会显示best|t,并且令人困惑。

    许多用户习惯于 Backspace Space Backspace 每个要删除的字符键入一次,以便使用空格替换/销毁坏字符;即,手动擦除它们。最终(1979 年或 1980 年代初),开发人员让步了,将其自动化:

    当您按下退格键时,内核 tty 行规则会通过打印(在简单的情况下)Ctrl-H、一个空格,然后是另一个 Ctrl-H 来消除您之前的字符。
    资料来源:当您在输入文本时键入退格键时,Unix 如何删除内容

    其中“Ctrl-H”是退格的控制代码。

    在某些情况下,您可以关闭此选项并通过键入stty -echoe ( echoe = “echo erase”,-表示“不要这样做”) 来获取旧行为。
    ____
    1实际上,在早期,退格不是退格——但那是另一回事了。

    • 4

相关问题

  • 语法错误:fd 编号错误?

  • traceroute,只打印网关信息

  • 如何在 ssh 上运行一瞥?

  • 备份 Nand Flash 存储区

  • 为什么 ssh 实用程序被视为 pty?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve