In C how do you redirect stdin/stdout/stderr to files when making an execvp() or similar call?
我有以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| pid_t pid = fork();
if (pid == -1)
{
// ...
}
else if (pid == 0)
{
stdin = someopenfile;
stdout = someotherfile;
stderr = somethirdopenfile;
execvp(args[0], args);
// handle error ...
}
else
{
// ...
} |
问题是execvp()调用的输入/输出仍然是控制台,而不是文件。 显然我做错了什么,正确的方法是什么?
正确的方法是使用dup2()用打开的文件替换文件描述符STDIN_FILENO,STDOUT_FILENO和STDERR_FILENO。 然后,您还应该在子进程中关闭原始文件:
1 2 3 4 5 6 7 8 9 10 11
| else if (pid == 0)
{
dup2 (fileno (someopenfile ), STDIN_FILENO );
dup2 (fileno (someotherfile ), STDOUT_FILENO );
dup2 (fileno (somethirdopenfile ), STDERR_FILENO );
fclose(someopenfile );
fclose(someotheropenfile );
fclose(somethirdopenfile );
execvp (args [0], args );
// handle error ...
} |
-
dup2()会失败吗?
-
大多数系统调用都会失败。 dup2(2)也不例外。 特别是达到文件描述符限制时,它可能会因errno == EMFILE而失败(您可以使用内置的ulimit bash或setrlimit(2) syscall降低此限制)。 阅读kernel.org/doc/man-pages/online/pages/man2/dup2.2.html
-
这样做之前是否不需要关闭原始stdinouterr?
-
@rustyx:否,dup2()如果打开则先关闭目标文件描述符。
-
您如何还原呢?
看一下freopen函数。
我必须对stdout做类似的事情,并编写了两个对我有用的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| static int fd ;
static fpos_t pos ;
void switchStdout (const char *newStream )
{
fflush(stdout );
fgetpos(stdout , &pos );
fd = dup (fileno (stdout ));
freopen(newStream ,"w", stdout );
}
void revertStdout ()
{
fflush(stdout );
dup2 (fd , fileno (stdout ));
close (fd );
clearerr(stdout );
fsetpos(stdout , &pos );
} |
您可以在stdin,stdout,stderr处于终端状态时使用此命令
1 2 3 4 5 6 7 8 9 10 11
| //change stdin,stdout,stderr
freopen("new_stdin","r",stdin );
freopen("new_stdout","r",stdout );
freopen("new_stderr","r",stderr );
//----do something;
//reset stdin,stdout,stderr
freopen("/dev/tty","r",stdin );
freopen("/dev/tty","r",stdout );
freopen("/dev/tty","r",stderr ); |
-
有关详细信息,请参见freopen手册页。 man freopen