从ls > log.txt谈起
ls > log.txt是什么意思?我们先来看看现象
我们当前所处的目录有以下文件/文件夹
接着我们执行 ls > log.txt
我们发现:
当前目录下创建了log.txt文件,log.txt存储了ls命令执行的结果。这是怎么一回事呢?
我们把这种现象成为“输出重定向”
以ls>log.txt为例,他把本该输出到显示器的内容输出到了log.txt文件里了。所以才会发生上述现象。
那么它是怎样实现的呢?
让我们来看看下面这段代码:
open:
【open函数是一个系统调用接口,其功能是打开或有可能创造一个文件/设备,其函数原型如下(open是一个重载函数,下面这个open用来创建文件),
解释一下这几个参数:
pathname:传一个文件名
flags:以哪些方式打开文件(O_WRONLY(只读),O_CREAT(不存在则创建文件)O_TRUNC(每次打开文件时清空文件)等等)
mode:设置文件权限
返回值:
返回一个文件描述符,它是非负的整数,被用于read、write等系统调用。成功返回的文件描述符会是最小的、当前没有为该进程所打开的文件描述符
】
write:
【write是往一个文件描述符(实际是往这个描述符随对应的文件)中写入buf所指向的内容,至多count个字节
函数原型:
返回值:
成功写入的字节个数,失败返回-1.
】
这段代码在干什么:
是往log1.txt文件里面写入msg指向的内容,程序运行结果如下
我们可以看到,hello,linux的内容已经被写入到log1.txt里了
接下来我们将上述代码稍作改变。
把fd,换成了1
再次编译运行
hello,linux直接打印在了显示器上。据此我们可以猜测,内容写到哪里,与这个fd有很大关系。
fd是什么:
第一句话的意思是,将buf指向的至多count个字节内容写到由文件描述符fd指代的文件中去,也就是说fd是对文件的指代,相当于一个映射,比如fd等于1,1号文件对应显示器文件
(操作系统会默认将0 1 2分配给键盘文件、显示器文件、显示器文件,也就是说0 1 2默认是打开的,且分别存储了这三个文件的地址)
fd 文件
0 键盘文件
1 显示器文件
2 显示器文件
下图阐述了操作系统是如何管理文件的
在pcb中(为什么在pcb中,因为文件常常是由进程进行访问的)有一个struct files_struct类型的指针,顾名思义,它指向struct files_struct类型的结构体,在该结构体内,存储了一个指针数组,这个数组的下标就是我们说的fd,数组元素就是指向文件结构体的地址。(进程每访问一个文件就创建该文件的结构体,并在struct files_struct中为它分配一个数组下标,即fd)
回答开头说的 ls>log.txt的实现原理:
把1所对应的显示器文件地址更改成log.txt文件地址,这个就是它实现的基本原理
那么要如何实现“更改”呢?这需要用到我们的系统调用接口dup2,它可以实现我们的期望。
(dup2,将oldfd指向的内容覆盖到newfd指向的内容,即newfd指向的内容会变成oldfd指向的内容
)
请看如下2段代码
他们的区别就是第二段代码加了dup2,将1所在文件地址改成fd所在文件地址。
运行结果
代码1(写在显示器)
代码2(将本该写到显示器的内容写到了log1.txt中)
由此,通过偷梁换柱,实现了开头所讲的效果。