C dup2/dup-为什么需要复制文件描述符?

C dup2/dup-为什么需要复制文件描述符?,c,linux,operating-system,system-calls,C,Linux,Operating System,System Calls,我试图理解dup2和dup的用法 从手册页: DESCRIPTION dup and dup2 create a copy of the file descriptor oldfd. After successful return of dup or dup2, the old and new descriptors may be used interchangeably. They share locks, file position pointers and flags; for exam

我试图理解
dup2
dup
的用法

从手册页:

DESCRIPTION

dup and dup2 create a copy of the file descriptor oldfd.
After successful return of dup or dup2, the old and new descriptors may
be used interchangeably. They share locks, file position pointers and
flags; for example, if the file position is modified by using lseek on
one of the descriptors, the position is also changed for the other.

The two descriptors do not share the close-on-exec flag, however.

dup uses the lowest-numbered unused descriptor for the new descriptor.

dup2 makes newfd be the copy of oldfd, closing newfd first if necessary.  

RETURN VALUE

dup and dup2 return the new descriptor, or -1 if an error occurred 
(in which case, errno is set appropriately).  
为什么我需要那个系统调用?复制文件描述符有什么用

如果我有文件描述符,为什么要复制它

如果您能解释一下,并给我举一个需要
dup2
/
dup
的例子,我将不胜感激


谢谢,dup用于重定向进程的输出


例如,如果要保存进程的输出,复制输出(fd=1),将复制的fd重定向到文件,然后分叉并执行进程,当进程完成时,再次将保存的fd重定向到输出。

dup系统调用复制现有的文件描述符,返回一个新的 引用相同的底层I/O对象

Dup允许Shell实现如下命令:

ls existing-file non-existing-file > tmp1  2>&1
2>&1告诉shell给命令一个与描述符1重复的文件描述符2。(即stderr和stdout指向同一fd)。
现在,tmp1文件中显示了对不存在的文件调用ls的错误消息以及对现有文件调用ls的正确输出

以下示例代码在连接标准输入的情况下运行程序wc 到管道的读取端

int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;
pipe(p);
if(fork() == 0) {
    close(STDIN); //CHILD CLOSING stdin
    dup(p[STDIN]); // copies the fd of read end of pipe into its fd i.e 0 (STDIN)
    close(p[STDIN]);
    close(p[STDOUT]);
    exec("/bin/wc", argv);
} else {
    write(p[STDOUT], "hello world\n", 12);
    close(p[STDIN]);
    close(p[STDOUT]);
}
该子项将读取端复制到文件描述符0上,关闭文件删除 p中的脚本程序和wc中的执行程序。当wc从其标准输入读取时,它从 管道。
这就是使用dup实现管道的方式,dup的一次使用现在你使用管道构建其他东西,这就是系统调用的美妙之处,你使用已经存在的工具构建一件又一件的东西,这些工具是使用其他东西构建的,等等。。 最后,系统调用是内核中最基本的工具


干杯:)

复制文件描述符的另一个原因是将其与
fdopen一起使用
fclose
关闭传递给
fdopen
的文件描述符,因此如果您不想关闭原始文件描述符,必须首先使用
dup
复制它。

请注意与dup/dup2相关的一些要点

dup/dup2-从技术上讲,其目的是通过不同的句柄在单个进程中共享一个文件表条目。(如果我们正在分叉,描述符在子进程中默认是重复的,并且文件表条目也是共享的)

这意味着我们可以使用dup/dup2函数为单个打开的文件表条目提供多个可能具有不同属性的文件描述符

(尽管目前似乎只有FD_CLOEXEC标志是文件描述符的唯一属性)

除了dup2和fcntl之间的一些errno值之外,差异是(最后一个) close后跟fcntl可能会引发竞争条件,因为涉及两个函数调用

详情可从

使用示例-

在shell中实现作业控制时的一个有趣示例,其中dup/dup2的使用可以在下面的链接中看到


如果没有
dup
dup2
,您将如何实现外壳的管道功能?您需要调用
管道(2)
,然后将其中一个文件描述符
复制到例如
STDIN\u FILENO
可能重复的
fdopen()
似乎不会复制文件描述符,它只是在用户空间中创建缓冲区。您误读了我的答案。关键是,在将fd传递给
fdopen
之前,您可能希望
dup
fd,因为
fclose
将关闭它。@offerit32:如果分配
文件
句柄以通过stdio接口访问预先存在的打开文件,则需要调用
fclose
以取消分配该
文件
句柄。如果您希望继续使用底层打开的文件,或者如果您的软件体系结构使得文件描述符的原始“所有者”代码将
close
它,那么
fclose
也将关闭您交给
fdopen
的底层文件描述符这一事实就是一个问题。您可以通过使用
dup
为同一打开的文件创建一个新的文件描述符以传递给
fdopen
,从而
fclose
不会关闭原始文件来避免此问题。关键是fdopen()将fd的所有权移动到
文件,而不是复制它。这是用户应该注意的。除
文件
对象外,需要保留可用
fd
句柄的使用者必须复制
fd
。就这些。@ConradMeyer:是的,这是一个很好的表达方式,需要注意的是,一旦您将所有权移动到
文件
中,就不会有任何操作将所有权从文件
中移开。所以
dup
对调用方很有帮助,而不是
ls
程序本身?如果已经可以访问文件,在像ls这样的程序中使用
dup
有什么好处吗?例如,这里,
ls
将错误写入硬编码的
2
,因此作为
ls
的消费者,我有办法克服它。我认为这是一个微妙的问题不?你的示例程序似乎有一个bug;您正在调用
dup(p[STDIN])
但随后丢弃了结果。您是否打算使用
dup2(p[STDIN],0)
?@Quuxplusone
dup
返回“进程当前未使用的编号最低的描述符”。由于fd 0刚刚关闭,
dup
应返回0
dup2
明确说明了应该使用哪种fd,而不仅仅是使用最低的免费fd,所以我更愿意这样做。@Wodin:啊,我打赌OP的想法你是对的。不过,我是否也对,“刚刚关闭”是相对的,并且OP的代码可能会在出现(例如)可能也正在打开文件的并发线程时中断?@qux
dup(fd) is equivalent to fcntl(fd, F_DUPFD, 0);

dup2(fildes, fildes2); is equivalent to 

   close(fildes2);
   fcntl(fildes, F_DUPFD, fildes2);