我写了一个简单的程序:
#include<stdio.h>
#include<unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int main(){
int fd = open("theFile.txt", O_CREAT | O_RDWR, 0666);
if(fd<0){
printf("coudlnt open File descriptor \n");
}
pid_t pid = fork();
if(pid==0){
dup2(int oldFD, int newFD);
dup2(fd,1);
execlp("/bin/ls","ls","-l", NULL);
}
return 0;
}
我想要的是,将
ls - l
的输出重定向到一个名为“the file.txt”的文件。代码按我的预期工作。令我困惑的是dup2
参数的顺序。我认为正确的顺序应该是dup2(1, fd)
-把fd
看作newFD
而1
看作oldFD
。但当我使用它作为dup2(fd,1)
时,代码就工作了,根据其他一些答案,它基本上是fd的标准输出。这里的
oldFD
fd
如何,这里的newFD
1
如何?如果1
是newFD
,为什么这个程序首先工作?另外,
execlp
在我调用dup2
后覆盖子地址空间。如何将dup2
连接到execlp
以便获得所需的结果。也就是说,我所做的cat theFile.txt
直接列出了电流。我能在这里得到一些解释吗?
最佳答案
根据[man7]: DUP(2):
int dup2(int oldfd,int newfd);
...
dup()系统调用创建文件描述符oldfd的副本,
使用编号最低的未使用文件描述符
描述符。
...
dup2()系统调用执行与dup()相同的任务,但是
在使用编号最低的未使用文件描述符时,它使用
在newfd中指定的描述符号。如果文件描述符newfd
以前是打开的,在被重新使用之前它是静默关闭的。
当将数据(例如文本)输出到控制台时,应用程序使用stdout流(同样是stderr,但为了简单起见,让我们忽略它)。stdout的fileno为1(最好使用常量而不是值,因为值可能会发生变化-在这种情况下不太可能,但通常情况下):
cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q048923791$ cat /usr/include/unistd.h | grep STDOUT
#define STDOUT_FILENO 1 /* Standard output. */
在您的子进程中,
ls
(viaexeclp
)将其数据发送到stdout(fileno 1)。在此之前,将进行dup2
调用。当前的情况,在调用dup2
之前(为了清楚起见,我将在引用stdout的fileno时使用定义的宏):fd
:指向自定义文件(以前打开过)STDOUT_FILENO
:指向标准输出dup2
呼叫:dup2(fd, STDOUT_FILENO)
(现在的情况):关闭当前STDOUT_FILENO
,并将fd
复制到STDOUT_FILENO
。现状:fd
:指向自定义文件STDOUT_FILENO
:指向自定义文件dup2(STDOUT_FILENO, fd)
:关闭当前fd
并将STDOUT_FILENO
复制到fd
。现状:fd
:指向标准输出STDOUT_FILENO
:指向标准输出如图所示,对于#1.,当数据将输出到stdout时,它实际上将转到自定义文件(而不是#2)。即使在使用
fd
时,它也会转到stdout。关于第二个问题:
[man7]: EXEC(3):
exec()系列函数替换当前进程映像
一个新的过程图像。本手册中描述的功能
页面是execve(2)的前端。
[man7]: EXECVE(2):
默认情况下,文件描述符在execve()中保持打开状态。
...
POSIX.1说如果文件描述符0、1和2
否则在成功执行execve()后关闭,并且进程
将获得权限,因为设置用户ID或设置组ID模式
在执行的文件上设置了位,然后系统可以打开
未指定这些文件描述符的文件。作为将军
原则上,任何可移植程序,无论是否有特权,都不能
假设这三个文件描述符在
一个execve()。
文件描述符将从子进程传递到
ls
。下面是您的代码(code.c)的改进版本(仅作细微更改):
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
int main() {
int ret = 0, fd = open("thefile.txt", O_CREAT | O_RDWR, 0666);
if (fd < 0) {
printf("Coudln't open file: %d\n", errno);
ret = 1;
}
pid_t pid = fork();
if (pid == 0) {
// dup2(int oldFD, int newFD);
if (dup2(fd, STDOUT_FILENO) < 0) {
printf("Couldn't redirect stdout: %d\n", errno);
ret = 2;
}
execlp("/bin/ls", "ls", "-l", NULL);
} else if (pid < 0) {
printf("Couldn't spawn child process: %d\n", errno);
ret = 3;
}
return ret;
}
关于c - dup2参数顺序困惑,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48923791/