文章目录
- 一、概念
参考书籍:《Linux Shell核心编程指南》——丁明一
一、概念
文件描述符是一个非负整数,内核需要通过这个文件描述符才可以访问文件
文件描述符好比一本书的目录(索引),通过这个索引可以找到需要的内容
在Linux系统中内核默认为每个进程创建三个标准的文件描述符:分别是0(标准输入)、1(标准输出)、2(标准错误)。通过查看/proc/PID/fd目录下的文件,就可以查看每个进程拥有的所有文件描述符
例如:查看当前shell的文件描述符
255是一个小技巧,bash用于在重定向时保留这些副本.
当打开文件时,系统内核会为特定的进程自动创建对应的文件描述符
示例:使用vi打开一个文件
再开启第二个终端窗口,查看vi进程的进程号
查看文件描述符
vi进程除了拥有三个标准文件描述符外,还有一个4号文件描述符,该描述符索引/var/log/.messages.swp文件。vi程序默认将所有的修改都写入该文件,只有在vi中执行保存命令才会将数据同步到/var/log/messages。
1.1.特点
优点
1、基于文件描述符的I/O操作兼容POSIX标准。
2、在UNIX、Linux的系统调用中,大量的系统调用都是依赖于文件描述符。
缺点
1、在非UNIX/Linux操作系统上(如Windows NT),无法基于这一概念进行编程。
2、由于文件描述符在形式上不过是个整数,当代码量增大时,会使编程者难以分清哪些整数意味着数据,哪些意味着文件描述符。因此,完成的代码可读性也就会变得很差。
二、手动创建文件描述符
2.1.语法
2.1.1.创建
exec 文件描述符 <> 文件名
2.1.2.调用
&文件描述符
2.1.3.关闭
exec 文件描述符<&-或
exec 文件描述符>&-
2.2.重定向输出的文件描述符
touch test.txt
exec 12>test.txt #创建仅可输出的文件描述符
接下来就可以通过文件描述符去操作文件
echo hello >&12
echo world >&12
cat test.txt
cat <&12 #不支持输入
exec 12<&- #关闭输出文件描述符
echo bob >&12 #关闭后无法再使用该描述符
2.3.重定向输入的文件描述符
exec 13<test.txt
cat <&13 #注意,文件仅可以被读取一次
exec 13<&- #关闭输入文件描述符
2.4.既可以输出又可以输入的文件描述符
exec 14<>test.txt
cat <&14
echo bob >&14
cat test.txt
exec 14<&-
三、使用read命令读取文件描述符
echo 'line1
> line2
> line3' > new.txt
exec 12<new.txt
read -u12 content #读取一行的值并赋值给content
[root@localhost tmp]# echo $content
line1
read -u12 content #再读取一行
[root@localhost tmp]# echo $content
line2
read -u12 content #读取最后一行
[root@localhost tmp]# echo $content
line3
cat <&12 #cat也无法读取任何内容
exec 12<&-
从上面的实验可以看出,文件描述符不是简单地对应一个文件的,还包含很多文件相关的信息,如权限、文件偏移量等。
文件偏移量更像一个指针,默认该指针指向的是文件的起始位置,当使用read命令读取一行数据后,该指针会指向下一行数据,再使用read读取一行数据,指针再往下移动一行,依次类推,直到文件结束。
如图:
而使用cat命令会读取文件的全部内容,文件描述符的指针会一次性跳到文件的末尾。
read命令还可以通过-n选项指定读取任意字符的数据
exec 12<new.txt
read -u12 -n1 content
[root@localhost tmp]# echo $content
l
read -u12 -n1 content
[root@localhost tmp]# echo $content
i
不仅查看内容会导致指针移动,写入数据也会导致指针移动。
创建文件描述符时,如果文件描述符对应的文件不存在,系统会自动创建一个新的空文件。
exec 12<>file.txt
echo Linux >&12
echo windows >&12
cat <&12 #通过文件描述符查看为空
cat file.txt #查看文件内容正常
exec 12<&-