文件描述符 | 缩写 | 描述 |
0 | STDIN | 标准输入 |
1 | STDOUT | 标准输出 |
2 | STDERR | 标准错误 |
1、STDIN
STDIN文件描述符代表shell的标准输入。对终端界面来说,标准输入是键盘。shell从STDIN 文件描述符对应的键盘获得输入,在用户输入时处理每个字符。
在使用输入重定向符号(<)时,Linux会用重定向指定的文件来替换标准输入文件描述符。 它会读取文件并提取数据,就如同它是键盘上键入的
2、STDOUT
STDOUT文件描述符代表shell的标准输出。在终端界面上,标准输出就是终端显示器。shell 的所有输出(包括shell中运行的程序和脚本)会被定向到标准输出中,也就是显示器。
通过输出重定向符号,通常会显示到显示器的所有输出会被shell重定向到指定的重定向文件。你也可以将数据追加到某个文件。这可以用>>符号来完成
3、STDERR
shell对于错误消息的处理是跟普通输出分开的。如果你创建了在后台模式下运行的shell脚 本,通常你必须依赖发送到日志文件的输出消息。
STDERR文件描述符代表shell的标准错 误输出。shell或shell中运行的程序和脚本出错时生成的错误消息都会发送到这个位置。
默认情况下,STDERR文件描述符会和STDOUT文件描述符指向同样的地方(尽管分配给它们 的文件描述符值不同)。也就是说,默认情况下,错误消息也会输出到显示器输出中
4、重定向错误、数据
4.1 只重定向输出
使用重定向输出符号> 或者追加>>
4.2 只重定向错误
STDERR文件描述符被设成2。可以选择只重定向错误消息,将该文 件描述符值放在重定向符号前。该值必须紧紧地放在重定向符号前,否则不会工作。
例:
ls -al badfile 2> test
现在运行该命令,错误消息不会出现在屏幕上了。该命令生成的任何错误消息都会保存在输 出文件中。
4.3 重定向错误和数据
ls -al test test2 test3 badtest 2> test6 1> test7
shell利用1>符号将ls命令的正常输出重定向到了test7文件,而这些输出本该是进入STDOUT 的。所有本该输出到STDERR的错误消息通过2>符号被重定向到了test6文件
也可以将STDERR和STDOUT的输出重定向到同一个输出文件。为此bash shell 提供了特殊的重定向符号&>
$ ls -al test test2 test3 badtest &> test7
当使用&>符时,命令生成的所有输出都会发送到同一位置,包括数据和错误。为了避免错误信息散落在输出文件中,相较于标准输出,bash shell自动赋予了错误消息更高的优先级。
5、重定向输出
5.1 临时重定向
echo "This is an error message" >&2
这行会在脚本的STDERR文件描述符所指向的位置显示文本,而不是通常的STDOUT
如果像平常一样运行这个脚本,你可能看不出什么区别。
$ cat test8
#!/bin/bash
# testing STDERR messages
echo "This is an error" >&2
echo "This is normal output"
$ ./test8
This is an error
This is normal output
默认情况下,Linux会将STDERR导向STDOUT。但是,如果你在运行脚本时重定向了 STDERR,脚本中所有导向STDERR的文本都会被重定向。
$ ./test8 2> test9
This is normal output
$ cat test9
This is an error
5.2 永久重定向
如果脚本中有大量数据需要重定向,那重定向每个echo语句就会很烦琐。取而代之,你可 以用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符。
$ cat test10
#!/bin/bash
# redirecting all output to a file exec 1>testout
echo "1"
echo "2"
echo "3"
$ ./test10
$ cat testout
1
2
3
exec命令会启动一个新shell并将STDOUT文件描述符重定向到文件。脚本中发给STDOUT的所 有输出会被重定向到文件
6、重定向输入
通过输入重定向,当使用read命令时就不必从键盘处读取数据,而是指定的文件处
exec 0< testfile
这个命令会告诉shell它应该从文件testfile中获得输入,而不是STDIN。这个重定向只要 在脚本需要输入时就会作用
$ cat test12
#!/bin/bash
# redirecting file input
exec 0< testfile count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
$ ./test12
Line #1: This is the first line.
Line #2: This is the second line.
Line #3: This is the third line.
将STDIN重定向到文件后, 当read命令试图从STDIN读入数据时,它会到文件去取数据,而不是键盘。
7、创建自己的重定向
7.1 创建输出文件描述符
exec 3>test13out
echo "and this should be stored in the file" >&3
和标准的文件描述符一样,一旦将另一个文件 描述符分配给一个文件,这个重定向就会一直有效,直到你重新分配
exec 3>>test13out
7.2 重定向文件描述符
exec 3>&1
exec 1>test14out
exec 1>&3
第一个exec将文件描述符3重定向到文件描述符1 的当前位置,也就是STDOUT。这意味着任何发送给文件描述符3的输出都将出现在显示器上。
第二个exec命令将STDOUT重定向到文件,shell现在会将发送给STDOUT的输出直接重定向到 输出文件中。但是,文件描述符3仍然指向STDOUT原来的位置,也就是显示器。如果此时将输出 数据发送给文件描述符3,它仍然会出现在显示器上,尽管STDOUT已经被重定向了
第三个exec将STDOUT重定向到文件描述符 3的当前位置(现在仍然是显示器)。这意味着现在STDOUT又指向了它原来的位置:显示器
( 个人理解,这个用法相当于运算时由于需要临时将变量A初始值赋给变量B,此时B的值就是A初始值,随后将变量A值更换掉,最后因为需要所以将变量B值(即A的初始值)又赋给A )
7.3 创建输入文件描述符
exec 6<&0
exec 0< testfile
exec 0<&6
可以用和重定向输出文件描述符同样的办法重定向输入文件描述符。在重定向到文件之前, 先将STDIN文件描述符保存到另外一个文件描述符,然后在读取完文件之后再将STDIN恢复到它 原来的位置
7.4 创建读写文件描述符
exec 3<> testfile
read line <&3
echo "This is a test line" >&3
由于你是对同一个文件进行数据读写,shell会维护一个 内部指针,指明在文件中的当前位置。任何读或写都会从文件指针上次的位置开始。如果不够小 心,它会产生一些令人瞠目的结果。
创建读写文件描述符时,如果文件有三行数据,仅读了文件的一行数据,此时指针指向了第二行数据的第一个字符,如果此时对文件进行写入内容,将会覆盖掉文件本来该位置的内容。
7.5 列出打开的文件描述符
能用的文件描述符只有9个,你可能会觉得这没什么复杂的。但有时要记住哪个文件描述 符被重定向到了哪里很难。为了帮助你理清条理,bash shell提供了lsof命令
lsof打开正在使用的文件list open files
# lsof
该命令会产生大量的输出。它会显示当前Linux系统上打开的每个文件的有关信息。这包括 后台运行的所有进程以及登录到系统的任何用户。
有大量的命令行选项和参数可以用来帮助过滤lsof的输出。常用的有-p允许 指定进程ID(PID),-d允许指定要显示的文件描述符编号
要想知道进程的当前PID,可以用特殊环境变量$$(shell会将它设为当前PID)。-a选项用来 对其他两个选项的结果执行布尔AND运算,这会产生如下输出
-p指定pid,-a是AND运算,-d指定文件描述符

或者通过查看/proc/$$/fd文件来查看正在使用的文件描述符


7.6 关闭文件描述符
要关闭文件描述符,将它重定向到特殊符号&-。脚本中看起来如下:
exec 3>&-
在关闭文件描述符时还要注意另一件事。如果随后你在脚本中打开了同一个输出文件,shell 会用一个新文件来替换已有文件。这意味着如果你输出数据,它就会覆盖已有文件