Shell、TTY子系统、终端的概念和作用
Linux系统的交互式命令行的组成
Linux系统的交互式命令行由Shell和TTY子系统构成实现。
Shell和TTY子系统的概念和作用
Shell是一个运行于用户空间的应用程序,它负责命令的解析、执行和执行结果的输出,它需要有设备为它提供命令内容的输入和接收它的输出,这个设备就由TTY子系统来提供。TTY子系统是一个分层的框架结构,我们可以把TTY子系统看成是面向对象编层中的一个类,这个类的一个实例就是一个TTY设备,一个TTY设备对应于一个设备文件。Shell如果要进入输入输出操作,那么去操作这个TTY设备文件就可以了。
上面这段话大家可以结合下面这幅TTY子系统的框架结构图来理解:
终端的概念和作用
终端有两个含义,我们这里先说它在TTY框架中的含义,另一个含义放到下一个目录中讲。
终端在TTY框架中的含义如下:
终端是TTY子系统中的概念,它位于“TTY I/O”层和“行规程(line discipline)”层之间,它实际上可以看成是“TTY I/O”层的输入/输出接口。
从图中我们可以看到,终端层根据底层的设备数不同,具体的实现结构也不一样,对应的终端类型也不一样。
情况一:底层设备为1个的情况:
比如运行在开发板上的Linux系统,键盘和显示器借用的是PC的,开发板与PC之间通过串口来进行通信,所以对于运行在开发板上的Linux系统,完成一条命令的输入和输出显示需要的只是1个串口设备而已,此时终端层的具体实现为空,即终端层不需要额外的代码(无实际功能),此时串口的输入和输出经行规程(line discipline)处理后,直接就送给了“TTY I/O”层。这种情况下的终端被称为叫“串口终端”。
情况二:底层设备为2个的情况:
比如在PC上运行的Ubuntu中的交互式命令行,则需要键盘和显示器一起,才能实现一条命令的输入和输出显示,此时终端对应的底层实现设备有两个,即键盘和显示器,此时就需要终端层提供一个有实际功能的终端,把这两个底层设备在逻辑上合并在一起后提供给“TTY I/O”层。这种情况下的终端被称为叫“虚拟终端”,又称为虚拟控制台(virtual console)。
细说Shell的作用
然后再来细说下Shell。Shell负责命令的解析和执行,它是一个 用户空间的应用程序,它的任务是:
- 读取 TTY 设备传来的输入(命令)。
- 解析命令并执行(如
ls
、cd
、echo
)。 - 将执行结果传递给TTY设备。
- 处理管道、重定向、环境变量等(如
ls | grep txt
)。 - 提供交互功能(如命令补全、历史记录)。
两个实际的命令行交互例子
例子1:在PC上的Ubuntu上进行命令行交互
假设你在PC上的Ubuntu的命令行输入下面的命令:
ls -l
则内部发生的流程如下:
- 键盘输入
ls -l
,TTY 结构中的底层设备驱动(如keyboard.c
)捕获输入数据,并传递给TTY结构中的行规程。 - TTY结构中的行规程层→虚拟终端→“TTY I/O”层依次处理并传递数据,“TTY I/O”层最终把数据传递给用户空间的 Shell程序。
- Shell 解析命令
ls -l
,查找/bin/ls
并执行该程序。 ls
进程运行,产生文件列表输出,将数据写入标准输出(stdout)。- TTY结构中的“TTY I/O”层→虚拟终端→行规程层依次处理并传递数据,将数据传递给底层显示设备(如屏幕)。
- 用户看到
ls -l
结果,完成了一次命令行交互。
例子2:运行于开发板上的Linux系统利用PC上的SecureCRT完成命令行交互
假设你的嵌入式开发板通过串口与PC相连,并在SecureCRT中输入以下命令:
ls -l
则内部发生的流程如下:
- PC端SecureCRT输入
ls -l
,SecureCRT 通过串口将数据发送到嵌入式开发板。 - 嵌入式开发板的串口驱动(如
imx-serial.c
)接收数据,并传递给TTY子系统结构中的行规则层,由于没有实际的终端层,所以行规则层处理完后,直接将数据传递给“TTY I/O”层,TTY I/O”层最终把数据传递给用户空间的 Shell程序。说明一下:其实这个串口驱动也是基于TTY子系框架来进行编写和注册的。 - Shell 解析命令
ls -l
,查找/bin/ls
并执行该程序。 ls
进程运行,产生文件列表输出,将数据写入标准输出(stdout)。- TTY结构中的“TTY I/O”层将数据接收到后,由于没有实际的终端层,所以“TTY I/O”层直接将数据发给行规则层,行规则层处理完后,将数据传给串口。
- 串口收到待发送数据后,再把数据发送到PC端,PC端收到数据后再把数据传递给运行于PC上的SecureCRT 。
- SecureCRT 接收到数据后进行显示,用户在PC上看到
ls -l
结果,完成了一次命令行交互。
特别要注意:“终端”的另一个含义:表示Linux中的 “交互式命令行”
上面的介绍中,在TTY框架中有终端的概念,这个时候的终端是指TTY子系统中位于“TTY I/O”层和“行规程(line discipline)”层之间的层。
但“终端”这个词还有另一含义:即表示Linux中的 “交互式命令行”。
在下文的叙述中,你要需要根据实际情况去分区到底在具体环境中“终端”是什么含义。
为什么大家喜欢把“交互式命令行”称为叫终端(Terminal)?
我们在Ubuntu中如果要打开一个交互式命令行,通常是搜索Terminal,然后打开相应的程序:
从这个过程来看,在Ubuntu中,实际上是把“交互式命令行”的名字命名为“终端(Terminal)",为什么呢?
其实不为什么,就是大家习惯这样叫了,毕竟终端在Linux系统的“交互式命令行”实现中也是个关键因素嘛。
即然Ubuntu中把“交互式命令行”命名为“终端(Terminal)",那我们也就把其它情况下的“交互式命令行”也可以称为终端吧,比如SecureCRT打开的“交互式命令行”。事实上,大家也习惯把“交互式命令行”称为叫终端了。