我试图理解dup2
和dup
的用法。
从手册页:
描述
dup
和dup2
创建文件描述符的副本oldfd
。成功返回dup
或dup2
后,新旧描述符可以互换使用。它们共享锁、文件位置指针和标志;例如,如果通过对其中一个描述符使用lseek
修改文件位置,则另一个描述符的位置也会更改。但是,这两个描述符不共享 close-on-exec 标志。
dup
对新描述符使用编号最低的未使用描述符。
dup2
使newfd
成为oldfd
的副本,必要时首先关闭newfd
。返回值
dup
和dup2
返回新的描述符,如果发生错误,则返回 -1(在这种情况下,errno
设置正确(。
为什么需要该系统调用?复制文件描述符有什么用?如果我有文件描述符,我为什么要复制它?如果您能解释并给我一个例子,我将不胜感激,需要dup2
/dup
。
dup 系统调用复制现有的文件描述符,返回一个新的引用相同的基础 I/O 对象。
Dup 允许 shell 实现如下命令:
ls existing-file non-existing-file > tmp1 2>&1
2>&1 告诉 shell 为命令提供一个文件描述符 2,该描述符是描述符 1 的副本。(即stderr和stdout指向相同的FD(。
现在,在不存在的文件上调用ls的错误消息和现有文件上ls的正确输出显示在tmp1文件中。
以下示例代码在连接标准输入的情况下运行程序 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 worldn", 12);
close(p[STDIN]);
close(p[STDOUT]);
}
子将读取端 dup 到文件描述符 0 上,关闭文件 deP中的脚本和WC中的执行者。当 wc 从其标准输入读取时,它会从管。
这就是使用 dup 实现管道的方式,那么现在 dup 的一个用途你使用管道来构建其他东西,这就是系统调用的美妙之处,你使用已经存在的工具构建一个又一个的东西,这些工具反过来使用其他东西构建等等。最后,系统调用是你在内核中获得的最基本的工具
干杯:)
复制文件描述符的另一个原因是将其与 fdopen
一起使用。 fclose
关闭传递给fdopen
的文件描述符,因此,如果您不希望关闭原始文件描述符,则必须首先使用dup
复制它。
dup 用于能够重定向进程的输出。
例如,如果要保存进程的输出,则复制输出 (fd=1(,将复制的 fd 重定向到文件,然后分叉并执行进程,当进程完成后,再次将保存的 fd 重定向到输出。
与 dup/dup2 相关的一些要点可以注意
dup/dup2 - 从技术上讲,目的是通过不同的句柄在单个进程中共享一个文件表条目。(如果我们要分叉,则默认情况下在子进程中复制描述符,并且文件表条目也被共享(。
这意味着我们可以使用 dup/dup2 函数为单个打开的文件表条目提供多个文件描述符,这些描述符可能具有不同的属性。
(虽然目前似乎只有FD_CLOEXEC标志是文件描述符的唯一属性(。
http://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html
dup(fd) is equivalent to fcntl(fd, F_DUPFD, 0);
dup2(fildes, fildes2); is equivalent to
close(fildes2);
fcntl(fildes, F_DUPFD, fildes2);
差异是(最后一个(- 除了一些 errno 值 beteen dup2 和 fcntl关闭后跟 FCNTL 可能会引发竞争条件,因为涉及两个函数调用。
详细信息可从以下网址查看http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
使用示例 -
在 shell 中实现作业控制时的一个有趣示例,可以看到 dup/dup2 的使用。在下面的链接中
http://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html#Launching-Jobs