69

我知道dup/dup2做什么,但我不知道什么时候会使用它。

有什么实际的例子吗?

谢谢。

4

5 回答 5

70

一个示例使用是 I/O 重定向。为此,您创建一个子进程并关闭标准输入或标准输出文件描述符(0 和 1),然后对您选择的另一个文件描述符执行 dup(),该文件描述符现在将映射到最低的可用文件描述符,即在此案例 0 或 1。

使用它,您现在可以执行任何可能不知道您的应用程序的子进程,并且每当子进程在标准输出上写入(或从标准输入读取,无论您配置什么)时,数据都会被写入提供的文件描述符。

Shell 使用它来实现带有管道的命令,例如/bin/ls | more通过将一个进程的标准输出连接到另一个进程的标准输入。

于 2009-11-12T07:44:30.950 回答
28

了解 dup 和 dup2 的最佳方案是重定向。
我们需要知道的第一件事是系统有 3 个默认文件 ID(或指示输出或输入源的变量)来处理输入和输出。它们是stdin, stdout, stderr, 在整数中它们是0, 1, 2。大多数函数都喜欢fprintforcout直接输出到stdout.
如果我们想重定向输出,一种方法是给函数,例如,给fprintf函数更多的参数来指示inout
但是,还有一种更优雅的方式:我们可以覆盖默认的文件 id,使它们指向我们想要接收输出的文件。dupdup2在这种情况下工作。
现在让我们从一个简单的例子开始:假设我们要将输出重定向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

  1. 这只是给出了一个直观的解释,您可能需要查看手册页或详细信息。实际上,我们在这里说“复制”,他们并没有复制所有内容。

  2. 这里的文件 id 是指文件的处理程序。上面提到的文件描述符是一个结构记录文件的信息。

于 2015-02-12T16:18:39.663 回答
10

当您对 POSIX 函数感到好奇时,尤其是那些看似重复的函数,通常最好检查一下标准本身。在底部,您通常会看到示例,以及两者的实现(和存在)背后的推理。

在这种情况下:

以下部分内容丰富。

例子

将标准输出重定向到文件

以下示例关闭当前进程的标准输出,重新分配标准输出以转到 引用的文件pfd,并关闭原始文件描述符以进行清理。

#include <unistd.h>
...
int pfd;
...
close(1);
dup(pfd);
close(pfd);
...

重定向错误消息

以下示例将消息从 重定向stderrstdout

#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 期。

于 2009-11-12T07:44:50.187 回答
5

一个实际的例子是将输出消息重定向到一些其他流,比如一些日志文件。这是 I/O 重定向的示例代码。
请参考这里的原帖

#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()");
}
于 2009-11-12T08:24:51.323 回答
3

shell 中的 I/O 重定向很可能使用 dup2/fcnlt 系统调用来实现。

我们可以使用 dup2 函数轻松模拟$program 2>&1 > logfile.log重定向类型。

下面的程序重定向标准输出和标准错误。即模拟$program 2>&1 > output使用 dup2 的行为。

#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
于 2018-06-20T22:45:54.287 回答