Linux 关闭后重新打开 stdout 和 stdin 文件描述符

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9084099/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 04:18:47  来源:igfitidea点击:

Re-opening stdout and stdin file descriptors after closing them

clinuxunix

提问by RegisteredUser

I'm writing a function, which, given an argument, will either redirect the stdout to a file or read the stdin from a file. To do this I close the file descriptor associated with the stdout or stdin, so that when I open the file it opens under the descriptor that I just closed. This works, but the problem is that once this is done, I need to restore the stdout and stdin to what they should really be.

我正在编写一个函数,给定一个参数,该函数要么将标准输出重定向到文件,要么从文件中读取标准输入。为此,我关闭了与 stdout 或 stdin 关联的文件描述符,以便当我打开文件时,它会在我刚刚关闭的描述符下打开。这有效,但问题是一旦完成,我需要将 stdout 和 stdin 恢复到它们真正应该的样子。

What I can do for stdout is open("/dev/tty",O_WRONLY); But I'm not sure why this works, and more importantly I don't know of an equivalent statement for stdin.

我可以为标准输出做的是 open("/dev/tty",O_WRONLY); 但我不确定为什么会这样,更重要的是我不知道 stdin 的等效语句。

So I have, for stdout

所以我有,对于标准输出

close(1);
if (creat(filePath, O_RDWR) == -1)
{
    exit(1);
}

and for stdin

和标准输入

close(0);
if (open(filePath, O_RDONLY) == -1)
{
    exit(1);
}

采纳答案by Ambroz Bizjak

You should use dup() and dup2() to clone a file descriptor.

您应该使用 dup() 和 dup2() 来克隆文件描述符。

int stdin_copy = dup(0);
int stdout_copy = dup(1);
close(0);
close(1);

int file1 = open(...);
int file2 = open(...);

< do your work. file1 and file2 must be 0 and 1, because open always returns lowest unused fd >

close(file1);
close(file2);
dup2(stdin_copy, 0);
dup2(stdout_copy, 1);
close(stdin_copy);
close(stdout_copy);

However, there's a minor detail you might want to be careful with (from man dup):

但是,您可能需要注意一个小细节(来自 man dup):

The two descriptors do not share file descriptor flags (the close-on-execflag). The close-on-exec flag (FD_CLOEXEC; see fcntl(2)) for the duplicate descriptor is off.

这两个描述符不共享文件描述符标志(close-on-execflag)。重复描述符的 close-on-exec 标志(FD_CLOEXEC;请参阅 fcntl(2))已关闭。

If this is a problem, you might have to restore the close-on-exec flag, possibly using dup3() instead of dup2() to avoid race conditions.

如果这是一个问题,您可能必须恢复 close-on-exec 标志,可能使用 dup3() 而不是 dup2() 以避免竞争条件。

Also, be aware that if your program is multi-threaded, other threads may accidentally write/read to your remapped stdin/stdout.

另外,请注意,如果您的程序是多线程的,其他线程可能会意外地写入/读取您重新映射的 stdin/stdout。

回答by cnicutar

I think you can "save" the descriptors before redirecting:

我认为您可以在重定向之前“保存”描述符:

int save_in, save_out;

save_in = dup(STDIN_FILENO);
save_out = dup(STDOUT_FILENO);

Later on you can use dup2to restore them:

稍后您可以使用dup2来恢复它们:

/* Time passes, STDIN_FILENO isn't what it used to be. */
dup2(save_in, STDIN_FILENO);


I am not doing any error checking in that example - you should.

我没有在那个例子中做任何错误检查 - 你应该这样做。

回答by reed_do_it

You could create a child process, and set up the redirection inside the child only. Then wait for the child to terminate, and continue working in the parent process. That way you don't have to worry about reversing your redirection at all.

您可以创建一个子进程,并仅在子进程中设置重定向。然后等待子进程终止,继续在父进程中工作。这样您就完全不必担心反转您的重定向。

Just look for examples of code using fork() and wait ().

只需查找使用 fork() 和 wait() 的代码示例。