execve 重定向到哪个文件描述符?

To which file descriptor execve redirect?

int main (void) {

   int rc=fork();
   if(rc==0){
   close(1); //close stdout BEFORE opening my file
   open("./c.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);


   //execve "wc"
   char *cmd[3];
   cmd[0] = strdup("wc"); //file to execuable
   cmd[1]=strdup("c.c"); //first arg to command 'wc' -> c.c
   cmd[2]=NULL;

   execvp(cmd[0], cmd);
   }

如果我关闭 () 标准输出,那么 execve ("wc") 的输出将在文件 c.txt 中,但前提是我在打开 () 之前关闭标准输出。如果我在

之后调用它
open("./c.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
   close(1); 

然后 -> wc: write error: Bad file descriptor.

我读过,对于 open()(在我的情况下可能是 wc 输出)是 OS 从 0 到达文件描述符,因此它首先找到 1 作为标准输出到 printf() 到屏幕。所以我需要 close() 它,以便使用来自 open("./c.txt") for wc 的文件描述符。但如果那是正确的(我不知道我在哪里理解正确),那么我在 open() 调用之前或之后关闭 stdout 并不重要,不是吗?一旦关闭,OS 就没有其他 FD 可以用作输出。可能我没看清楚。

问题:为什么必须先关闭 fd1 才能重定向到 c.txt?

首先要建立的几个概念。

  1. stdout 是作为程序启动的一部分自动打开的流之一。程序启动代码使用文件描述符 1 for stdout).
  2. execve 使用与 parent/calling 进程相同的打开文件描述符创建一个新进程(可以从 execve man page.
  3. open 将寻找要使用的 lowest available file descriptor

好的,现在开始你的代码。

案例 1 - 关闭、打开、执行

在这种情况下,会发生以下事件序列:

  1. 程序开始于 stdout=>fd 1
  2. close(1) 使 fd 1 可用。
  3. open("c.txt") returns 1 有效地将 stdout 重定向到文件。
  4. execve 创建一个新进程,其中 1 打开并重定向到文件。
  5. wc 写入 fd 1 现在在文件中结束。

案例 2 - 打开、关闭、执行

在这种情况下,会发生以下事件序列:

  1. 程序开始于 stdout=>fd 1
  2. open("c.txt") 被调用但 fd 1 不可用所以它 returns 2.
  3. close(1) 意味着现在实际上没有 stdout.
  4. execve 创建一个在 fd 1 上没有开放流的新进程(即没有 stdout)。
  5. wc 尝试写入 fd 1 并收到 bad file descriptor 错误,因为 fd 1 未打开。