基本概念
1. 文件描述符
总览: 当一个程序成功向操作系统请求访问一个打开的文件, 内核会返回一个指向内核中全局文件表(global file table)中的入口点(entry)的文件描述符. 文件表入口点包含如: 文件的inode(硬盘中的位置), 字节偏移量(byte offset), 以及对这个数据流的访问限制(只读, 只写等). 整个过程如下图所示:文件描述符: 是计算机操作系统中被打开文件的唯一标识. 它用来描述一种数据资源, 以及这个数据资源可以如何被访问到当一个程序请求打开一个文件或者读取某个数据资源时, 比如 socket, 操作系统的内核通常会做以下几件事:允许访问在全局文件表中创建一个入口点为这个程序提供访问入口点的位置描述符由唯一非负整数标识, 如 1, 2, 567... 对于每个被打开的文件, 至少有一个文件描述符.
2. stdin stdout stderr
在 *Unix 系统当中, 前三个文件描述符0, 1, 2 默认为 stdin stdout stderr比如使用终端时, 默认情况下:1. stdin 从键盘读取
2.stdout, stderr 输出至屏幕流(stream)的概念: 可以理解为数据的传递和走向. 比如 从键盘输入字符到 stdin, 数据经过 stdin 然后到达某个程序, 被程序处理之后需要展示的数据流向 stdout 或者 stderr(如果有错误产生), 最后屏幕显示相关的 stdin 和 stderr(如果有错误产生).
理解 stdout 和 stderr 的区别:
虽说在使用终端时, 两者都会输出到屏幕, 但是二者是源自不同的文件描述符, 也就是数据流(data stream)不一样.
比如在shell当中使用 ls 命令跟着一个不存在的文件时, 屏幕会显示如下, 这里显示的内容属于 stderr 数据流: ls: 无法访问'dne.file': 没有那个文件或目录jovy@Jovy-element:~$ ls dne.file
如果我在当前目录下新建一个 test.txt 文件, 在使用 ls 命令, 会得到如下结果: jovy@Jovy-element:~$ ls text.txt text.txtjovy@Jovy-element:~$ touch text.txt
这时候屏幕上不会显示错误信息, 因为没有 stderr 的数据流产生, 屏幕输出了默认的 stdout 数据流.
3. 重定向文件描述符
在Linux 当中,>,>>,<,<<是和重定向有关的符号.
针对第一个例子,我们把stderr 重定向到/dev/null 当中, 观察屏幕输出的内容:
jovy@Jovy-element:~$ ls dne.file 2>/dev/null jovy@Jovy-element:~$
发现刚才的错误信息不见了, 这是因为 stderr 信息流被重定向到 Linux 当中的特殊设备"/dev/null"去了.
"/dev/null"的意思是--"go nowhere", 哪儿也不去,就像一个黑洞一样.
再试试把第二个例子当中的标准输出重定向到 capture.txt 文件当中:
jovy@Jovy-element:~$ ls text.txt 1>capture.txtjovy@Jovy-element:~$ jovy@Jovy-element:~$ cat capture.txt text.txt
发现在执行完ls命令之后,屏幕输出text.txt, 然后使用 cat 命令查看stdout 重定向后的文件, 发现了 "text.txt" . 也就是说成功把stdout的数据流定向到capture.txt这个文件当中. 默认情况下,1>capture.txt
中的 1 可以被省略, Linux 默认为标准输出重定向 .
好,还是上面的例子, 使用ls dne.file
尝试显示一个不存在的文件, 但是我们给标准输出 stdout 做重定向到 stdout.txt:
jovy@Jovy-element:~$ ls dne.file >stdout.txtls: 无法访问'dne.file': 没有那个文件或目录jovy@Jovy-element:~$ cat stdout.txt jovy@Jovy-element:~$
发现重定向标准输出后, 屏幕显示的还是错误信息, 查看stdout.txt的信息发现没有任何记录.
因此, 这个例子可以表明 stdout 和 stderr 两个的区别是属于不同的两个数据流.
总结
理解清楚文件描述符的概念,理解Linux内核如何运用文件描述符。在此基础上,认清楚stdin, stdout, stderr 三个数据流的作用,就能理解什么是stdin,stdout,stderr啦。