bash的文件描述符与重定向
本文简要的描述linux中文件的描述符与重定向.
文件描述符
文件描述符是一个整数代号,代表对某个文件的操作. 它的范围从零开始, 最大值与操作系统支持打开的文件数量有关.
通常使用的就是三个整数, 0/1/2. 0: 标准输入, 例如键盘输入这种, stdin 1: 标准输出, 例如显示在屏幕上, stdout 2: 标准错误, 通常也显示在屏幕上, stderr.
文件描述符是一个指针数组的下标
linux/unix 系统中, 万物皆文件, 各个设备的操作也被抽象并统一成为对文件(file)的操作.
系统对内存中打开的每一个文件, 都有一个file对象作为操作文件的接口.
系统如果开始一个新进程, 同样会建立一个PCB对象来描述该进程相关信息. 而在PCB中采用一个指针数组 file* fa_array[]来指向进程所使用的各个file对象.
这个指针数组的下标就是文件描述符. 0/1/2 就对应系统占用的三个默认文件.
重定向
shell中的程序的输入输出大部分围绕字符展开, 默认输入是通过键盘的”标准输入”进入程序,相应的文件描述符为0, 默认输出到屏幕,也就是标准输出, 相应的文件描述符为1.
改变这种默认的输入输出方向的行为就是重定向. 也就是修改进程PCB中指针数组中的指针,让它指向一个新的文件.
重定向的命令格式
bash中的重定向相关的符号是小于号小于号, 比如 “>”,”»”, “<”, “»”.
最常见的命令格式如下
cmd 1> log 2> errlog
上述命令表示重定向cmd的输出结果到log文件中, 错误信息输出到errlog文件中.
其中 > 符号表示重定向输出, 前面的 1/2 分别是上文提到的文件描述符.
起到类似功能的重定向符号有”»” 与 “<” 其中”»“也是输出重定向,和”>”的差异在于, “»“是在原文件尾部追加, 而”>”是覆盖原文件. “<” 是输入重定向.
一些特殊的重定向应用
一些缩写
:>
表示一个空输出
&>
中的&表示标准输出与标准错误.
匿名输入重定向
用户如果需要把某个文件foo的内容传递给命令bar. 可以利用管道(pipe)实现,那么命令如下:
cat foo | bar
同样可以利用输入重定向, 那么命令可以写成:
bar <foo
但如果此时需要传递给bar的内容不再是某个特定文件而是另外一个命令cmd的输出, 那么就需要匿名管道与输入重定向的结合了.
bar <(cmd)
here document 当前文档
当前文档也是输入重定向的一个应用, 使用在用户需要输入多行内容的时候.
一般的输入, 使用回车换行, 命令就直接执行了.这时候就需要使用here document .
它的格式如下
foo << eof
xxxx
xxxx
eof
它以输入重定向符号”«“开始,紧接着一个用户指定的分隔符eof, 这个分隔符不能是空格或者tab.
然后就是用户的输入, 这时候可以用回车来分开各行的内容.
等到用户再次输入分隔符的时候, 输入结束.
这些重定向符号在使用的时候要注意和文件描述符之间不能有空格
修改系统默认的重定向通道
为了改变默认的文件操作”通道”,需要用到”>&”这个符号, 它的用法如下:
a>&b
这个命令中, ab都是代表文件描述符的整数. 执行之后, a就复制为b.
也就是在文件指针数组中进行如下操作:
fd_array[a]= fd_array[b]
比如说如果希望标准错误也输出到标准输出, 那么可以使用以下命令:
2>&1
也就是fd_array[2]的值从标准错误的file对象变成 fd_array[1]的标准输出的file对象, 所以程序的错误信息原本是传送给标准错误的, 现在也一并输出到标准输出.
使用exec 来建立和修改文件描述符
以上的操作都是在现在的文件描述符里进行更改. 用户如果想建立新的文件描述符, 需要使用exec 命令.
比如
exec 2> foo.file
那么就是把标准错误(2) 重定向到文件 foo.file 中.
exec命令与文件描述符复制命令”>&” 组合, 可以用于创建描述符的一个拷贝.
比如
exec 88>& 2
就是把标准错误复制到88这个描述符里面去.
而
exec 88>&-
则是删除88这个描述符.
小结
文件描述符作为进程结构体PCB中文件指针数组的下标,它影响到文件操作的方方面面. 尤其是系统占用的0/1/2 这三个关键的文件描述符.
用户可以通过”>””<”, “>&”这样的操作符有限的修改相关的描述符. 并使用exec来建立和删除新的文件描述符.