我写了这个简单的程序:
#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
的输出重定向到名为“theFile.txt”的文件。该代码按我的预期工作。这里让我困惑的是 dup2 参数的顺序。我相信正确的顺序应该是 dup2(1, fd)
- 将 fd
视为 newFD
并将 1
视为oldFD
。但是当我将它用作 dup2(fd,1) 时,代码可以工作,根据 SO 上的一些其他答案,它基本上是 fd 的标准输出。
这里的oldFD
fd
怎么样,这里的newFD
1
怎么样?如果1
是newFD
,为什么这个程序首先可以工作?
此外,在我调用 dup2
后,execlp
会覆盖子进程的地址空间。 dup2
如何连接到 execlp
以获得所需的结果。即我所做的 cat theFile.txt
我得到了当前直接列出的内容。
我可以在这里得到一些解释吗?
最佳答案
根据[man7]: DUP(2) :
int dup2(int oldfd, int newfd);
...
The dup() system call creates a copy of the file descriptor oldfd,
using the lowest-numbered unused file descriptor for the new
descriptor.
...
The dup2() system call performs the same task as dup(), but instead
of using the lowest-numbered unused file descriptor, it uses the file
descriptor number specified in newfd. If the file descriptor newfd
was previously open, it is silently closed before being reused.
将数据(例如文本)输出到控制台时,应用程序使用 stdout 流(也stderr,但为了简单起见,我们将其忽略)。 stdout 的 fileno 是 1 (最好使用常量而不是值,因为值可能会改变 - 在 this 中不太可能 情况,但一般而言):
cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q048923791$ cat /usr/include/unistd.h | grep STDOUT #define STDOUT_FILENO 1 /* Standard output. */
在您的子进程中,ls(通过execlp)将其数据吐出到stdout(文件号1) 。 在此之前,将进行dup2调用。当前情况,在dup2调用之前(为了清楚起见,我将在引用stdout的时使用定义的宏>文件号):
- fd:指向自定义文件(之前打开过)
- STDOUT_FILENO:指向stdout
dup2 调用:
dup2(fd, STDOUT_FILENO)
(就像现在一样):关闭当前的STDOUT_FILENO并将fd复制到 STDOUT_FILENO。目前情况:- fd:指向自定义文件
- STDOUT_FILENO:指向自定义文件
dup2(STDOUT_FILENO, fd)
:关闭当前fd并将STDOUT_FILENO复制到fd。目前情况:- fd:指向stdout
- STDOUT_FILENO:指向stdout
正如所见,对于#1.,当数据输出到stdout时,它实际上会转到自定义文件(与#2相反) . 它将转到 stdout,即使使用 fd)。
关于第二问题:
-
The exec() family of functions replaces the current process image
with a new process image. The functions described in this manual
page are front-ends for execve(2). -
By default, file descriptors remain open across an execve().
...
POSIX.1 says that if file descriptors 0, 1, and 2 would
otherwise be closed after a successful execve(), and the process
would gain privilege because the set-user-ID or set-group_ID mode
bit was set on the executed file, then the system may open an
unspecified file for each of these file descriptors. As a general
principle, no portable program, whether privileged or not, can
assume that these three file descriptors will remain closed across
an execve().
文件描述符将从子进程传递到ls。
以下是代码 (code00.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/