这两个函数包含在#include<unistd.h>之中。他们都是用来复制一个现有的文件描述符。

函数功能:若成功返回新的文件描述符,否则返回-1,并且dup返回的文件描述符一定是当前可用文件描述符中最小的。
dup2可以用newfd指定新描述符。若newfd已经打开,那么先将其关闭。若oldfd==newfd,那么返回newfd,不关闭它。这些返回的新文件描述符与参数oldfd指向同一个文件表,新的文件描述符的关闭操作总是由dup函数清除的。
一个进程内dup和dup2函数执行以后内核的数据结构如上图所示。文件描述符指向的是同一个文件表。也拥有相同的文件偏移量。下面是一个简单的实例。
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{//打开文件int fd = open("./1.txt",O_RDWR|O_APPEND|O_TRUNC);if (-1 == fd){perror("Open Failed");exit(-1);}//复制文件描述符int newfd = dup(fd);//写入文件int len;int size = write(fd,"Hello World!\n",len = strlen("Hello World!\n"));if (-1 == size){perror("Write Failed");exit(-1);}//读取文件并打印char str[50] = {0};lseek(fd,0,SEEK_SET);size = read(fd,str,len);printf("%s",str); //从复制的文件描述符读取文件并打印。size = read(newfd,str,len);printf("%s",str);return 0;
}
运行结果如下。
运行结果表明复制以后的文件描述符和原本的文件描述符拥有相同的文件偏移量,这就能够说明他们确实索引的是同一个文件表项。
dup和dup2常用在需要创建子进程的进程中。举个例子,将当前的环境变量保存到一个文件之中。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>int main(int argc,char *argv[])
{int statu;int fd = open("./env.txt",O_WRONLY | O_TRUNC| O_CREAT,0664);if(-1 == fd){perror("open fial");exit(1);}if(-1 == dup2(fd,STDOUT_FILENO)) //指定新的文件描述符是标准输出。{perror("dup fail");exit(1);}pid_t pid = fork();if (0 == pid){execl("/usr/bin/env","env",NULL); //启动env程序exit(0);}else if (0 < pid){wait(&statu); //等待子进程结束,并获取结束状态//打开标准输出设备,否则后面的printf无法打印到屏幕。fd = open("/dev/tty",O_RDWR,0664);dup2(fd,STDOUT_FILENO); //复制fd.if(0 == WEXITSTATUS(statu)){printf("已经成功将当前用户环境变量保存到文件env.txt中。\n");}}else{perror("fork fail");exit(1);}return 0;
}
运行结果如下:
通过shell命令env的输出结果成功保存到了env.txt中。