终端中的 ASCII 控制字符

终端中的 ASCII 控制字符

作者:Julia Evans | 2024年10月31日

我最近一直在思考终端的问题,昨天我对所有的"控制代码"(Control Codes,如 Ctrl-ACtrl-CCtrl-W 等)产生了好奇。它们到底是怎么回事?

ASCII 控制字符表

这里有一张包含所有 33 个 ASCII 控制字符的表格,以及它们在我的机器(macOS)上大致的用途。虽然这里面有无数的例外情况,但我会讨论一下它的含义以及我知道的该图表存在的所有问题。

不同种类的代码混在一起

这张图表让我感到惊讶的第一点是,这 33 个控制代码被(非常粗略地)分成了以下几类:

  1. 由操作系统终端驱动程序处理的代码 :例如,当操作系统看到 3 (Ctrl-C) 时,它会向当前程序发送 SIGINT 信号。
  2. 其余代码则按原样传递给应用程序 :应用程序可以随心所欲地处理它们。其中一些子分类包括:
    • 对应键盘按键的代码 :例如 EnterTabBackspace。例如,当你按下 Enter 时,你的终端会收到 13
    • Readline 使用的代码:"应用程序可以随心所欲"通常意味着"它或多或少会执行 readline 库所做的操作,无论应用程序是否真的使用了 readline"。所以我标记了一堆 readline 使用的代码。
    • 其他代码 :例如,我认为 Ctrl-X 在终端中通常没有标准含义,但 Emacs 非常频繁地使用它。

这些代码没有真正的结构,它们是随机散布的,因为这是有机演化而来的。

只有 33 个控制代码

另一件让我惊讶的事情是,只有 33 个控制代码------A 到 Z,再加上 7 个(@, [, \, ], ^, _, ?)。这意味着,如果你想在终端应用程序中使用 Ctrl-1 作为快捷键,那通常没有意义------至少在我的机器上,Ctrl-1 和直接按 1 是一样的,Ctrl-3Ctrl-[ 也是一样的。

此外,Ctrl+Shift+C 并不是一个控制代码------它的作用取决于你的终端模拟器。在 Linux 上,Ctrl-Shift-X 通常被终端模拟器用于复制、打开新标签页或粘贴,它根本不会发送到 TTY。另外,我经常使用 Ctrl+Left Arrow,但那也不是控制代码,它发送的是一个 ANSI 转义序列(ctrl-[[1;5D),这是另一回事,我们在这篇文章中没有空间讨论。这种"只有 33 个代码"的情况与 GUI 中的键盘快捷键完全不同,在 GUI 中你可以为任何按键设置 Ctrl+KEY

官方的 ASCII 名称对我来说意义不大

这 33 个控制代码在 ASCII 中都有名字(例如 3ETX)。当这些代码最初被定义时,它们根本不是用于计算机或终端的,而是用于电报机。电报机与 UNIX 终端不同,所以很多代码被重新定义了。我个人觉得这些 ASCII 名称没什么用,因为 50% 的情况下,ASCII 中的名称与该代码在当今 UNIX 系统上的实际作用毫无关系。所以忽略这些名称会更容易。

很难将 Ctrl-M 用作键盘快捷键

另一个奇怪的地方是 Ctrl-M 实际上就是 EnterCtrl-I 就是 Tab,这使得很难将它们用作快捷键。根据快速研究,似乎有些人确实还在使用 Ctrl-ICtrl-M 作为快捷键,但这需要你配置终端模拟器来区别对待它们。我的主要结论是:如果我写一个终端应用程序,我应该避免使用 Ctrl-ICtrl-M 作为快捷键。

如何识别发送了哪些控制代码

在写这篇文章时,我需要进行大量实验来弄清楚各种按键组合的作用,所以我写了这个 Python 脚本 echo-key.py 来打印它们。

关于规范模式与非规范模式的注意事项

表中的两个代码(Ctrl-WCtrl-U)被标记为"由操作系统处理",但实际上它们并不总是由操作系统处理,这取决于终端是否处于"规范模式"(canonical mode)还是"非规范模式"(noncanonical mode)。

  • 规范模式 下,程序仅在按下 Enter 后才获得输入(OS 负责处理 BackspaceCtrl-W)。
  • 非规范模式 下,程序在按下按键时立即获得输入,Ctrl-WCtrl-U 会被传递给程序处理。

关于"所有 OS 终端驱动程序代码都可以通过 stty 配置"

我提到 Ctrl-C 发送 SIGINT,但如果愿意,你可以使用 stty 工具重新映射所有标记为"OS 终端驱动程序"的代码。我个人从未重新映射过这些,也无法想象这样做的理由。

关于信号的注意事项

  • 如果关闭了 ISIG 终端模式,OS 就不会发送信号。例如,Vim 会关闭 ISIG
  • 在 BSD 系统上,有一个额外的控制代码 Ctrl-T,它发送 SIGINFO

存在很多冲突

由于"只有 33 个代码",系统中不同部分想要使用同一个代码的情况很多。例如,默认情况下 Ctrl-S 会冻结屏幕,但如果你关闭它,readline 就会用 Ctrl-S 进行向前搜索。

关于"Backspace"和"其他 Backspace"

在图表中,我将代码 127 标记为"Backspace",将 8 标记为"其他 Backspace"。这似乎是 Mastodon 回复中讨论最多的主题。

  • 在我的机器上:我按下 Backspace 键,TTY 收到字节 127 (DEL)。
  • 如果我按 Ctrl+H,在 readline 中它的效果与 Backspace 相同,但在没有 readline 支持的程序中,它只会打印出 ^H

总结

我可能忽略了更多关于"它在我的机器上如何工作"与"在别人机器上如何工作"的区别。虽然我觉得这些内容很有趣,但我不认为它们一定很有用。我在过去 20 年里成功地每天使用终端,而无需了解这些细节。但我很高兴能学习它,也许你也会觉得有趣。


转载:ASCII control characters in my terminal

相关推荐
HokKeung3 天前
用 Cobra 写一个像样的 Go 命令行工具
go·命令行
生活、追梦者5 天前
【Windows】 CMD 黑窗口命令大全
windows·命令行·cmd·运维技巧
花花无缺7 天前
Windows 定时执行 Python 脚本方案
python·操作系统·命令行
wangruofeng8 天前
终端里 rm 一下文件就没了,macOS 怎么删文件才进废纸篓
javascript·命令行·apple
Apifox11 天前
让 AI Agent 稳定使用 Apifox:新版 CLI + Skill 正式上线!
ai编程·测试·命令行
深度学习机器14 天前
Ghostty终端使用体验
人工智能·命令行
vortex515 天前
Shell 命令执行知识体系全景解析
linux·运维·bash·shell·命令行
你好潘先生17 天前
别再记命令了,用 yeero do 说句人话就能跑脚本,而且不烧 token
服务器·python·命令行
XIAOHEZIcode20 天前
Ubuntu 终端美化全栈指南:Bash 到 Kitty 踩坑实录
linux·ubuntu·命令行