结合自己的理解以及为了让自己容易去理解,并不保证完全正确性。

0x01 重定向、文件描述符、管道

文件描述符

首先,Linux的哲学之一即一切皆文件。

其次,系统若要操作一个文件,就必须明确的指定这个文件,这就涉及到如何标识文件。我们标识文件使用的是文件名,但文件名只是为了用户可读性,但是计算机不同,计算机考虑的是性能而不是可读性。

Linux使用文件描述符来标识一个文件,文件描述符实际是一个数字,不同的文件使用不同的数字来标识,Windows类似的是文件句柄。

在使用文件描述符时,直接使用会与真正的数字产生歧义,因此通过在数字之前使用&来标识该数字是文件描述符。

每个程序在运行前都会打开三个文件,分别是标准输入、标准输出、标准错误输出,文件描述符分别为0,1,2。

我们把这三个文件当作三块内存空间,系统用0,1,2来标识这三块内存空间,程序从文件描述符为0的内存空间读取数据作为程序的输入,把程序输出的数据输出到文件描述符为1的内存空间中,把错误信息输出到文件描述符为2的内存空间中。

简单说就是,程序在运行前会分配三块内存空间,然后分别标识为0,1,2,然后程序在运行时只管从标识符为0的内存读取数据,向标识符为0的内存输出数据,向标识符为2的内存输出错误信息。

两个问题:

  1. 不同的程序使用一样的0,1,2文件描述符来标识会导致混乱吗?

    不用担心一样的标识会导致混乱,因为我们知道进程之间的内存空间是隔离独立的。

  2. 为什么要用三块内存作为中间区域,以及为什么都规定它们的文件描述符为0,1,2?

    首先,采用中间区域的区域我想作用就是作为缓冲区。

    其次,之所以都要使用0,1,2来标识,我觉得可以从用户的角度出发,用户只需要操作0,1,2这三个文件操作符接口就可以了,至于这三个内存区域绑定了哪个文件就交给操作系统了。假设,如果这个过程交给用户,那么用户想要把数据输出打印到屏幕上,那么首先得获取显示器对应的文件描述符,而把这个过程交给操作系统,然后操作系统提供一个接口(即0,1,2文件描述符)给用户使用,大大减小了用户的工作。

重定向

根据上面我们的理解可知,程序只管对标识符为0,1,2的内存空间进行操作。那么有几个问题,程序从标识符为0的内存空间中读取数据,那么谁又向该内存空间写入数据呢?总不可能凭空产生吧。程序向标识符为1的内存空间输出数据,那么谁又会从该内存空间读取并使用里面的数据呢?标准错误输出同理。

为了解决上面的问题,这三块内存区域还应该与其他东西绑定,它们用于向这三块内存区域写入或读取数据。默认情况下,与标识符为0的内存空间绑定的标准输入设备就是键盘,与标识符为1的内存空间绑定的标准输出设备就是显示器,与标识符为2的内存空间绑定的标准错误输出设备也是显示器。

接下来我们回到这节的重点:重定向。

重定向可以理解为更改这三块内存空间绑定的对象。

输入重定向:<

输出重定向:>>>

错误重定向:2>2>>

例如cat test1.txt > test2.txt,就是把标识符为1的内存空间绑定的对象从显示器更改为了文件。其他同理。

对于0>&1这种操作的理解:

意思是将标识符为0的内存空间要绑定的对象改为标识符为1的内存空间当前绑定的对象。

注意,是当前的,意味是如果之后标识符为1的内存空间改变了绑定对象,并不会导致标识符为0的内存空间改变绑定对象。

管道

管道也可以理解为一块内存空间,这块内存空间绑定着前一个进程的标识符为1的内存空间以及后一个进程标识符为0的内存空间。即前一个进程输出的数据作为后一个进程的输入数据。

参考资料:

https://www.k0rz3n.com/2018/08/05/Linux%E5%8F%8D%E5%BC%B9shell%EF%BC%88%E4%B8%80%EF%BC%89%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6%E4%B8%8E%E9%87%8D%E5%AE%9A%E5%90%91/

最后更新: 2019年05月21日 11:13

原始链接: https://sakuxa.com/2019/03/29/文件描述符、重定向、管道浅析/