参考文章:
Linux下的管道编程技术-dup函数和dup2函数
http://www.xxlinux.com/linux/article/development/soft/20071214/13347.html
Linux下的管道编程技术
http://tech.it168.com/o/2006-11-07/200611061433947.shtml
http://publish.itpub.net/o/2006-11-07/200611061433947.shtml
Linux管道的实现机制
http://www.kerneltravel.net/kernel-book/%E7%AC%AC%E4%B8%83%E7%AB%A0%20%E8%BF%9B%E7%A8%8B%E9%97%B4%E9%80%9A%E4%BF%A1/7.1.1.htm
UNIX环境高级编程(第2版) 3.12 dup和dup2函数
http://book.csdn.net/bookfiles/418/10041815074.shtml
1、基本概念回顾
系统调用级概念--文件描述符/文件描述符表
0 标准输入
1 标准输出
2 标准错误
这三个文件描述符所指向的内核struct file结构默认指向的设备为进程所属终端,即tty、pst等等。
C运行库级概念--FILE结构
stdin 标准输入FILE结构指针,其所关联的文件描述符为0
stdout 标准输出FILE结构指针,其所关联的文件描述符为1
stderr 标准错误FILE结构指针,其所关联的文件描述符为2
C++标准库级概念--流
cin 标准输入流对象,其所关联的文件描述符为0
cout 标准输出流对象,其所关联的文件描述符为1
cerr 标准错误流对象,其所关联的文件描述符为2
FILE结构和流这两个概念都是在语言层次对系统调用级概念文件描述符的封装,没有本质的区别。
2、输入输出重定向的概念和目的
3、输入输出重定向的用法
command >file 2>&1,等价于command &>file
以w的方式(参见fopen文件打开模式)打开文件file,>file等价于1>file,首先将文件file对应的文件描述符的文件指针复制到文件描述符1,即重定向标准输出到文件file,接着将文件描述符1的文件指针复制到文件描述符2,即同时重定向标准错误到文件file。其本质工作原理是调用dup2函数。特别注意的是重定向的顺序,如果写成command 2>&1 >file,其意义是首先将标准错误重定向到标准输出(这个时候标准输出还是指向终端),接着将标准输出重定向到文件file,其最终表现是标准错误还是输出到终端,标准输出才是输出到文件file。反射
另外是以w的方式打开文件file的,所以file文件中只能记录command最后一次运行的标准输出和标准错误。
:>file 或 >file
这两个命令表示将文件file设置为空,即清空文件内容。如果文件不存在,则创建一个空文件(等同于touch命令)。
:表示一个空输出
这两个命令的唯一区别就是>file不是在所有shell中都可以正常工作。
command >>file 2>&1
以a的方式打开文件file,其他与上面的命令相同。>>file等价于1>>file。
由于是以a的方式打开文件file,所以command每次运行的标准输出和标准错误都记录在文件file中。
command <file
以r的方式打开文件file,<file等价于0<file,将文件file对应的文件描述符的文件指针复制到文件描述符0,即重定向标准输入到文件file,即标准输入将从文件file中读取。
exec
echo 123456789 >file #把字符串写到文件file中,文件file内容为123456789
exec 3<>file #把文件file以读写方式打开,并指定文件描述符为3
read -n 4 <&3 #从文件file中读4个字符,文件file的读写指针已经指到第四个字符末尾
echo -n . >&3 #在第5个字符处写一个点,覆盖第5个字符,-n表示不换行
exec 3>&- #关闭文件描述符3
cat file #文件file的内容现在变成了1234.6789
说明:
exec n<file 把文件file以读方式打开,并指定其文件描述符为n
exec n>file 把文件file以写方式打开,并指定其文件描述符为n
exec n<>file 把文件file以读写方式打开,并指定其文件描述符为n
exec n>&- 关闭输出文件描述符n
exec n<&- 关闭输入文件描述符n
exec 0<&- 或 exec <&- 关闭标准输入
exec 1>&- 或 exec >&- 关闭标准输出
注意:3-9号描述符都是保留给shell脚本使用的。
4、输入输出重定向的实现原理
输入输出重定向是通过在头文件unistd.h中定义的dup和dup2系统调用函数来实现的,定义如下:
#include <unistd.h>
int dup( int oldfd );
int dup2( int oldfd, int targetfd )
利用函数dup,我们可以复制一个描述符。传给该函数一个既有的描述符,它就会返回一个新的描述符,这个新的描述符是传给它的描述符的拷贝。这两个描述符指向同一个内核struct file结构。例如,如果我们对一个文件描述符执行lseek操作,得到的第一个文件的位置和第二个是一样的。下面是用来说明dup函数使用方法的代码片段:
int fd1, fd2;
...
fd2 = dup( fd1 );
需要注意的是,我们可以在调用fork之前建立一个描述符,这与调用dup建立描述符的效果是一样的,子进程也同样会收到一个复制出来的描述符。
dup2函数跟dup函数相似,但dup2函数允许调用者规定一个有效描述符和目标描述符的id。dup2函数成功返回时,目标描述符(dup2函数的第二个参数)将变成源描述符(dup2函数的第一个参数)的复制品,换句话说,两个文件描述符现在都指向同一个文件,并且是函数第一个参数指向的文件。下面我们用一段代码加以说明:
int oldfd;
oldfd = open("app_log", (O_RDWR | O_CREATE), 0644 );
dup2( oldfd, 1 );
close( oldfd );
本例中,我们打开了一个新文件,称为“app_log”,并收到一个文件描述符,该描述符叫做oldfd。我们调用dup2函数,参数为oldfd和1,这会导致用我们新打开的文件描述符替换掉由1代表的文件描述符(即标准输出)。任何写到标准输出的东西,现在都将改为写入名为“app_log”的文件中。需要注意的是,dup2函数在复制了oldfd之后,会立即将其关闭,但不会关掉新近打开的文件描述符,因为文件描述符1现在也指向它。