一个示例用途是I / O重定向。为此你分叉一个子进程并关闭stdin或stdout文件描述符(0和1)然后你在你选择的另一个filedescriptor上做一个dup(),它现在将被映射到最低的可用文件描述符,这是在这里案例0或1。
使用它,您现在可以执行任何可能不知道您的应用程序的子进程,并且只要子进程在stdout上写入(或从stdin读取,无论您配置什么),数据都会写在提供的文件描述符上。
Shell使用它来实现带管道的命令,例如/bin/ls | more
通过将一个进程的stdout连接到另一个进程的stdin。
理解dup和dup2的最佳方案是重定向。
首先我们需要知道的是系统有3个默认文件id(或指示输出或输入源的变量)来处理输入和输出。他们是stdin
,stdout
,stderr
,整数他们是0
,1
,2
。像fprintf
或cout
这样的大多数函数都直接输出到stdout
。
如果我们想重定向输出,一种方法是,例如,fprintf
函数更多参数指示in
和out
。
但是,有一种更优雅的方式:我们可以覆盖默认文件ID,使它们指向我们想要接收输出的文件。 dup
和dup2
正是在这种情况下工作。
现在让我们从一个简单的例子开始:假设我们想将fprintf
的输出重定向到名为“chinaisbetter.txt”的txt文件。首先,我们需要打开这个文件
int fw=open("chinaisbetter.txt", O_APPEND|O_WRONLY);
然后我们希望stdout
使用dup函数指向“chinaisbetter.txt”:
dup2(fw,1);
现在stdout(1)指向“chinaisbetter.txt”的描述符,即使它仍然是1,但输出现在被重定向。
然后您可以正常使用printf
,但结果将在txt文件中而不是直接显示在屏幕上:
printf("Are you kidding me? \n");
PS:
当你对POSIX函数感到好奇时,特别是那些看似自我复制的函数,对check the standard itself来说通常都是好的。在底部,您通常会看到示例,以及两者的实现(和存在)背后的推理。
在这种情况下:
以下部分内容丰富。
将标准输出重定向到文件
以下示例关闭当前进程的标准输出,重新分配标准输出以转到pfd
引用的文件,并关闭原始文件描述符以进行清理。
#include <unistd.h>
...
int pfd;
...
close(1);
dup(pfd);
close(pfd);
...
以下示例将消息从stderr
重定向到stdout
。
#include <unistd.h>
...
dup2(2, 1); // 2-stderr; 1-stdout
...
没有。
dup()
和dup2()
函数是多余的。他们的服务也由fcntl()
功能提供。它们已被包含在IEEE Std 1003.1-2001的这一卷中,主要是出于历史原因,因为许多现有的应用程序使用它们。
虽然所示的简短代码段与dup2()
的行为非常相似,但基于本卷IEEE Std 1003.1-2001中定义的其他函数的符合实现要复杂得多。最明显的是信号捕获函数的可能影响,可以在步骤之间调用并分配或释放文件描述符。阻止信号可以避免这种情况。
dup2()
函数没有标记为过时,因为它提供了fcntl()
在类型不安全版本中提供的类型安全版本的功能。它用于POSIX Ada绑定。
dup2()
函数不用于关键区域作为同步机制。
在[EBADF]的描述中,fildes超出范围的情况由fildes无效的给定情况涵盖。 fildes
和fildes2
的描述是不同的,因为与fildes2
相关的唯一无效性是它是否超出范围;也就是说,当fildes2
调用时,dup2()
是否引用一个打开的文件并不重要。
没有。
close()
,fcntl()
,open()
,IEEE Std 1003.1-2001,<unistd.h>
的基本定义量
首次发布在第1期中。来自SVID的第1期。
一个实际的例子是将输出消息重定向到某些其他流,如某些日志文件。以下是I / O重定向的示例代码。 请参考原帖here
#include <stdio.h>
main()
{
int fd;
fpos_t pos;
printf("stdout, ");
fflush(stdout);
fgetpos(stdout, &pos);
fd = dup(fileno(stdout));
freopen("stdout.out", "w", stdout);
f();
fflush(stdout);
dup2(fd, fileno(stdout));
close(fd);
clearerr(stdout);
fsetpos(stdout, &pos); /* for C9X */
printf("stdout again\n");
}
f()
{
printf("stdout in f()");
}
shell中的I / O重定向很可能是使用dup2 / fcnlt系统调用实现的。
我们可以使用dup2函数轻松模拟$program 2>&1 > logfile.log
类型的重定向。
下面的程序重定向stdout和stderr .i.e使用dup2模拟$program 2>&1 > output
的行为。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int
main(void){
int close_this_fd;
dup2(close_this_fd = open("output", O_WRONLY), 1);
dup2(1,2);
close(close_this_fd);
fprintf(stdout, "standard output\n");
fprintf(stderr, "standard error\n");
fflush(stdout);
sleep(100); //sleep to examine the filedes in /proc/pid/fd level.
return;
}
vagrant@precise64:/vagrant/advC$ ./a.out
^Z
[2]+ Stopped ./a.out
vagrant@precise64:/vagrant/advC$ cat output
standard error
standard output
vagrant@precise64:/vagrant/advC$ ll /proc/2761/fd
total 0
dr-x------ 2 vagrant vagrant 0 Jun 20 22:07 ./
dr-xr-xr-x 8 vagrant vagrant 0 Jun 20 22:07 ../
lrwx------ 1 vagrant vagrant 64 Jun 20 22:07 0 -> /dev/pts/0
l-wx------ 1 vagrant vagrant 64 Jun 20 22:07 1 -> /vagrant/advC/output
l-wx------ 1 vagrant vagrant 64 Jun 20 22:07 2 -> /vagrant/advC/output