「Linux」- 区分 console、terminal、shell、tty 含义

问题描述

经常听见人们提起 shell、terminal、console、tty 这些术语,但是界限非常模糊,心中不免疑惑:它们只是同种东西的不同名称么?如果不是,那么它们分别指的是什么呢?还有在命令 ps(1) 的输出中的 TTY 列代表着什么?而 pts 又是什么东西呢?我们将带着这些问题,从最易理解、最常用的开始,逐步梳理这些概念并进行区分。

在这个行当里,很多东西(概念)都有一段演变历史。当你知道了这段历史,你就知道了这个东西的由来。有些东西不是直接创造出来的,它们是演变来的。

Shell

Shell 是最容易理解的,之所以这么说是因为我们日常接触的最多、使用的最多。Shell 个程序(简单地说),命令行解释器,它获得键盘输入的命令并交由操作系统来执行。在 Linux 中,类似的程序有 bash,zsh,csh 等等,它们都是 Shell 程序。在 Windows 中,我们熟知的 CMD 程序就属于 Shell 程序。

在维基百科的描述中,Shell 是指访问计算机服务的用户接口,可以是命令行接口(CLI),也可以是图形化接口(GUI),这取决于计算机的用途与角色。之所以称之为 Shell 是因为它是操作系统的最外层。我们常说的 Shell 并不是它的标准定义,而是指命令行接口(CLI)。在过去里,这是用户可与操作系统交互的仅有方式。

但是注意 XTerm,GNOME Terminal,konsole,rxvt 这些并不是 Shell 程序,它们是终端仿真器(后面会介绍)。

TTY, Console and Terminal

它们是文本输入/输出环境。

计算机的早期……

在 1869 年发明 证券报价机,机电设备,由 打字机、很长的电线对、纸带打印机 组成,目的是为了在长距离内实时传送股票价格。这个概念渐渐地进化出更快的、基于 ASCII 码的 电传打字机

通过大型网络(Telex Network),电传打字机 被连接到世界各地,用于传送商业电报,但是此时的 电传打字机 还没有被链接到计算机上。

与此同时,计算机虽然体积庞大、价格昂贵,但是可以执行多任务、功能强大足以与用户实时交互。

当命令行模式替代旧时的批处理模式时,电传打字机被用作输入输出设备(因为因为它在市面上随处可见)。命令行属于交互模式,自然需要输入输出设备。

在市面上有很多类型的电传打字机,只是存在微小差异,因此需要引入软件兼容性层。在 Unix 中,由操作系统处理低层细节,诸如字长,波特率,流量控制,奇偶校验,基本行编辑的控制代码等。在 1970 年代后期,通过诸如 VT-100 之类的固态视频终端使花式光标移动、色彩输出、其他高级功能成为现实。

终端的使用案例(早期)


终端 ===物理线路===>>> UART(Universal Asynchronous Receiver and Transmitter,在计算机上) => UART driver(在内核中)

UART driver,管理字节的物理传输,包括奇偶校验、流控制。在简单的系统中,UART driver 随后会将传入字节直接传递给某些应用程序进程。但是这种方法将缺少以下基本功能:

# 行编辑:在输入错误时,需要进行删除。这可以由应用程序实现,但是在 Unix 的设计哲学中,应用程序应该保持简单。因此操作系统来提供编辑缓冲以及某些简单的编辑命令(删除键,删除单词,清除行,重新打印),这些默认在 line discipline 中是启用的。但是某些应用程序(Shell,Mail Client)需要自己处理行编辑,因此它们将 line discipline 切换为 raw 模式,而不使用默认的 cooked/canonical 模式。另外 line discipline 可能包含用于字符串回显、在 CR 与 LF 之间自动转换的选项。

内核提供几种不同的 line discipline,但是单次只能有某个连接到给定的串行设备。提供行编辑的 line discipline 被称为 N_TTY(drivers/char/n_tty.c)。其他 line discipline 用于其他目的,例如管理交换数据数据包(ppp,IrDA,serial mice)。

# 会话管理:用户可以运行多个程序,但是某个时刻只能与其中某个程序交互。某些时候用户可能需要结束某个程序,或者让程序休眠。在后台运行的程序因该保持执行,知道它们尝试向终端写入,此时应该暂停程序。同样的,用户输入只能重定向给前端运行的程序。操作系统在 TTY driver 中实现该功能。

操作系统进程在不断地执行,但是 TTY dirver 只有在被调用时才会执行,line discipline 也是如此。

UART driver,Line discipline,TTY dirver 这三者合在一起被称之为 TTY device,或者简称为 TTY。

通过操作 /dev 下的设备文件,进程可以影响 TTY device 行为,当然这需要具有设备文件的写入权限。因此在用户登录时,用户必须成为该设备文件的所有者,正也是 login 程序的工作,使用 root 权限运行,然后提示用户登录。

当然实际的物理线路可能会复杂些:

但是也没有太大的变化,除了操作系统必须处理 Modem 挂起的情况。

典型的桌面系统(现代)

随着技术进步,很多东西都已经被替代,我们很难见到电传打字机、视频终端。我们现在见到的 TTY 都是视频终端的模拟,通过软件模拟实物。正如我们所见到的那样,概念一直保留到现在。

下面是 Linux 控制台的工作流程:

如图所示 TTY driver 与 line discipline 如同以前,但是 UART、Terminal 已经不存在了。取而代之的是使用软件模拟视频终端,并渲染到VGA 显示器。

控制台子系统有些僵化。如果将终端仿真移到用户区,事情将变得更加灵活(抽象)。下面是 XTerm 以起复制程序的工作图:

为了将终端仿真移动到用户空间,并保留 TTY 子系统(会话管理,行编辑),因此 pseudo terminal 或 pty 被发明。

# 旧的内容 #

Consle,TTY,Terminal,它们密切相关。本来它们指的是与计算机交互的一台设备:在 Unix 早期中,是电传打印机(Teleprinter)样式的设备,像打字机(Typewriter),有时称为电传打字机(teletypewriter, tty)。“Terminal”是从电子的角度看,而“Console”是从家具的角度看。在 UNIX 很早的时期,电子键盘和显示器成为终端(Terminal)的常态。

Wikipedia/System console 中, “It is a physical device consisting of a keyboard and a screen, and traditionally is a text terminal, but may also be a graphical terminal. “,所以说终端是某种由键盘、屏幕组成的物理设备。

现代操作系统……

TTY,在 UNIX 术语中是一种特定类型的设备文件,它实现许多在读写之外的附加命令(ioctl)。在多数情况下,Terminal 与 TTY 同义。有些 TTY 由内核提供,代表一台硬件设备,例如来自键盘的输入与去往屏幕的输出。其他 TTY,有时称为 pseudo-ttys,由终端仿真器提供,比如 XTerm、Scrre、SSH 等等。

Terminal 还有设备的更传统含义 —— 通过设备可以与计算机交互,通常是键盘与显示。例如,X Terminal 是一种瘦客户端,是一种特殊用途的计算机,只用于驱动键盘、鼠标、显示器及其他设备,而实际的应用程序运行在其他远程计算机中。

Console 通常是物理意义上的终端,在某些定义中是直连到机器的终端。在操作系统中,Console 作为 TTY 出现。在某些系统(Linux,FreeBSD)中,Console 作为 TTY 出现(可以使用快捷键切换);有时候称之为 “console”, ”virtual console”, ”virtual terminal”或者其他的名字,都是在指同种东西。

所以对于我们这些软件层面的用户来说,可以将 TTY,Terminal,Console 视为同等事物,即用于访问计算机的终端设备。而终端仿真器其实也是在仿这三者(如果等同视之),因此我们只需要区分 Terminal 与 Shell 即可。

虚拟终端(Virtual Console)

什么是“真实终端”?如上所述,“真实终端”是访问计算机的终端物理设备。以前的计算机价格昂贵且体积巨大,不能直接放在室内而需要通过终端设备进行访问 —— 这就是需要物理终端的原因。

现在计算机已经非常便宜且体积小巧,已经无需连接物理终端进行访问,但是键盘显示等物理设备还是存在的,所以说终端的概念还是存在的。当我们提到虚拟终端时,则是指提供相同功能的程序。

所以,在 ps(1) 中,输出的 TTY 字段是指连接到系统的虚拟终端。

Terminal Emulator – 终端仿真器

终端仿真器(terminal emulator)是程序,它也属于虚拟终端。运行该程序将打开单个窗口,并让你与 Shell 程序交互。现在有很多终端仿真程序,比如 gnome-terminal, konsole, xterm 等等。

可以说终端仿真器是有图形化界面的 TTY,他们之间的不同在于:TTY 是由操作系统提供的;终端仿真器是运行在 TTY 上的(该 TTY 运行图形化子系统)。

另外注意,终端仿真器是在仿物理终端设备,并不是在仿 Shell,它负责运行 Shell 程序并显示给用户以用于交互操作。

关于 Terminal 与 Shell 的任务

键盘输入:Terminal 将按键转为控制序列(e.g. Left\e[D),然后 Shell 将控制序列转换为命令(e.g. \e[Dbackward-char

屏幕输出:Shell 发出诸如显示字符串、修改字体背景色、移动光标等等指令,Terminal 则采取相应行动。

复制粘贴:比如 GNOME Terminal 的 Ctrl+Shift+V / Ctrl+Shift+P 等等,完全是在 Terminal 中的概念。在 Shell 中,可能也有复制粘贴的概念,比如 Ctrl+Y / Meta+W 等等。这属于不同机制,虽然行为结果是相同的。

命令提示:如 root@laptop # 样,完全是在 Shell 中的概念。

作业控制(aka. Job Control):完全是在 Shell 中的概念。

命令输出:Shell 永远都不知道命令执行后的输出(除非重定向),输出历史(滚动功能)是在 Terminal 中的概念。

相关链接

SECURITY NOW / episodes 233, 235, 237, 239 and 241

参考文献

Wikipedia/Shell (computing)
What is “the Shell”?
Wikipedia/System console
What is the exact difference between a ‘terminal’, a ‘shell’, a ‘tty’ and a ‘console’?
Why is a virtual terminal “virtual”, and what/why/where is the “real” terminal?
The TTY demystified
Wikipedia/TTY