dup和dup2也是两个很实用的调用,它们的做用都是用来复制一个文件的描写叙述符。数据结构
它们经常常使用来重定向进程的stdin、stdout和stderr。这两个函数的原形例如如下:app
#include <unistd.h> int dup( int oldfd ); int dup2( int oldfd, int targetfd );
传给该函数一个既有的描写叙述符,它就会返回一个新的描写叙述符,这个新的描写叙述符是传给它的描写叙述符的拷贝。这意味着,这两个描写叙述符共享同一个数据结构。好比,假设咱们对一个文件描写叙述符运行lseek操做,获得的第一个文件的位置和第二个是同样的。如下是用来讲明dup函数用法的代码片断:
函数
int fd1, fd2; ... fd2 = dup( fd1 );
dup2()函数:
dup2函数跟dup函数类似,但dup2函数赞成调用者规定一个有效描写叙述符和目标描写叙述符的id。dup2函数成功返回时,目标描写叙述符(dup2函数的第二个參数)将变成源描写叙述符(dup2函数的第一个參数)的复制品,换句话说,两个文件描写叙述符现在都指向同一个文件,并且是函数第一个參数指向的文件。如下咱们用一段代码加以说明:
spa
int oldfd; oldfd = open("app_log", (O_RDWR | O_CREATE), 0644 ); dup2( oldfd, 1 ); close( oldfd );
如下咱们介绍一个更加深刻的演示样例代码。回顾一下命令行管道,咱们可以将ls –l命令的标准输出做为标准输入链接到wc –l命令。接下来。咱们就用一个C程序来加以说明这个过程的实现。代码例如如下所看到的。命令行
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { int pfds[2]; if ( fork() == 0 ) { close(1); dup2( pfds[1], 1 ); close( pfds[0] ); execlp( "ls", "ls", "-l", NULL ); } else { close(0); dup2( pfds[0], 0 ); close( pfds[1] ); execlp( "wc", "wc", "-l", NULL ); } return 0; }
以后,当即关掉管道的输入端。而后,使用execlp函数把子进程的映像替换为命令ls –l的进程映像,一旦该命令运行,它的不论什么输出都将发给管道的输入端。
现在来研究一下管道的接收端。从代码中可以看出,管道的接收端是由父进程来担当的。首先关闭stdin描写叙述符,因为咱们不会从机器的键盘等标准设备文件来接收数据的输入,而是从其余程序的输出中接收数据。code
而后,再一次用到dup2函数。让管道的输入端做为输入,这是经过让文件描写叙述符0(即常规的stdin)重定向到pfds[0]实现的。关闭管道的stdout端(pfds[1]),因为在这里用不到它。最后,使用 execlp函数把父进程的映像替换为命令wc -l的进程映像,命令wc -l把管道的内容做为它的输入。blog