在C中重定向子进程的文件输出
Posted
技术标签:
【中文标题】在C中重定向子进程的文件输出【英文标题】:Redirecting file output of subprocess in C 【发布时间】:2016-06-17 00:43:06 【问题描述】:我要么完全忘记了我想知道的关于 C 的一切,要么出现了严重错误。我想将子进程(stdout 和 stderr)的输出重定向到文件。我是这样做的:
if ((pid = fork()) == 0)
get_host_date(today) ;
int fd = open(log_filename, O_RDWR | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) ;
dup2(fd, STDOUT_FILENO) ; // make stdout go to file
dup2(fd, STDERR_FILENO) ; // make stderr go to file
fprintf(stderr, "This is a message") ;
if ((status = execv(command, argv)) == -1)
printf("\n\nError: execve failed for %s", command) ;
perror("\nexecve failure: ") ;
exit(EXIT_FAILURE) ;
close(STDOUT_FILENO) ;
close(STDERR_FILENO) ;
日志文件按指定创建,但输出未转到该文件。我做了一些测试输出 (fprintf(stderr, "This is a message") ;),但这并没有出现在任何地方。 Wenn 我检查了变量 fd,我看到它的值是 1(紧接在 open 之后)。但是 1 不应该是预定义的输出文件描述符吗?
有人可以帮我吗?我尝试了一切,但没有结果。
非常感谢您 最良好的祝愿 约尔格
P.S.:我正在使用 RHEL 和 GNU-C。
好的,这里有一个不适合我的压缩代码:
int main(int argc,
char* argv[])
PROC_REC proc ;
strcpy(proc.command, "/home/islk/entw/v0816/exe/islk_server") ;
strcpy(proc.args[0], "ISLK_DB1_SERV01") ;
strcpy(proc.args[1], "") ;
strcpy(proc.env[0], "ISLKSERVER_NR=5") ;
strcpy(proc.env[1], "") ;
ISLK_start_single_process(&proc) ;
exit(EXIT_SUCCESS) ;
static long ISLK_start_single_process(PROC_REC *prec_ptr)
long i=0 ;
int status ;
char *argv[16] ;
char command[256], log_filename[128], today[DB_DATE_DOM] ;
pid_t pid ;
/* Set arguments */
for (i=0; i<16; i++)
if (strcmp(prec_ptr->args[i], "") != 0)
argv[i] = prec_ptr->args[i] ;
else
argv[i] = NULL ;
/*******************/
/* Set environment */
/*******************/
for (i=0; i<16; i++)
if (strcmp(prec_ptr->env[i], "") != 0)
putenv(prec_ptr->env[i]) ;
/*****************/
/* Start process */
/*****************/
if ((pid = fork()) == 0)
get_host_date(today) ;
bs_create_filename(log_filename, "islk$log", "", "%s_%8.8s.log",
prec_ptr->args[0], today) ;
int fd = open(log_filename, O_RDWR | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) ;
int fdo = dup2(fd, STDOUT_FILENO) ; // make stdout go to file
int fde = dup2(fd, STDERR_FILENO) ; // make stderr go to file
close(fd) ;
fprintf(stdout, "This is a message") ;
if ((status = execv(command, argv)) == -1)
printf("\n\nError: execv failed for %s", command) ;
perror("\nexecv failure: ") ;
exit(EXIT_FAILURE) ;
close(STDOUT_FILENO) ;
close(STDERR_FILENO) ;
else if (pid < 0)
printf("\n\nError: fork failed for %s", prec_ptr->args[0]) ;
perror("\nfork failure: ") ;
return ERROR ;
else
printf("\nProcess %d started for %s", pid, prec_ptr->args[0]) ;
prec_ptr->pid = pid ;
return NO_ERROR ;
尝试了以下方法:
dup2(fd, STDERR_FILENO) ;
dup2(fd, STDOUT_FILENO) ;
-> 到 stderr 的消息被写入文件,而不是到 stdout
dup2(fd, STDOUT_FILENO) ;
-> 到 stderr 的消息被写入终端,到 stdout 无处
dup2(fd, STDOUT_FILENO) ;
dup2(STDERR_FILENO, STDOUT_FILENO) ;
-> 到 stderr 的消息被写入文件,到终端上的标准输出
dup2(fd, STDERR_FILENO) ;
dup2(STDOUT_FILENO, STDERR_FILENO) ;
-> 到 stderr 的消息被写入文件,到终端上的标准输出
-> 标准输出似乎有问题!
【问题讨论】:
我无法重现您的问题。请提供minimal reproducible example。如果我添加“明显”位以使您的代码可以干净地编译,它会按预期运行。 也许使用fileno
来确定整数描述符。你也应该在dup2
之后关闭 fd。而且我不确定您是否可以将一个文件用于两个流。
我认为你是对的,fd == 1
是问题的一部分。似乎stdout
之前已被您的进程或其父母之一关闭,并且那里发生的任何事情也可能阻止您的重定向工作(例如dup2(1, 1);
没有意义,但我不知道它是否会伤害)
离题:close()
命令永远不会被执行。如果exec..()
成功,它将永远不会返回,如果失败,您将在调用close()
之前exit()
ing
总是检查错误。请为每个函数添加适当的检查,并报告您的发现(包括errno)
【参考方案1】:
我认为您几乎已经通过检测fd == 1
“在 open() 之后立即”回答了这个问题。根据the dup2() man page:
dup2() 系统调用执行与 dup() 相同的任务,但取而代之的是 使用编号最小的未使用文件描述符,它使用 newfd 中指定的描述符编号。如果描述符 newfd 是 之前打开的,在重新使用之前会静默关闭。
因此,如果 fd == 1
并且您调用 dup2( fd, STDOUT_FILENO );
则 STDOUT_FILENO(也为 1)关闭,重定向文件的描述符也是如此。如果您无法找出为什么 stdout 在您的程序环境中关闭,也许您可以在调用dup2()
之前进行测试:
if( fd != STDOUT_FILENO )
dup2( fp, STDOUT_FILENO );
至少这应该作为一个技巧来检查我是否正确。
【讨论】:
我发现了为什么 fd == 1(之前关闭了 stdout&stderr)。但我改变了这个(现在 fd == 3 打开后)。到目前为止,我已经正确编写了 stderr。但是到标准输出的消息不会出现在输出文件中,即使我只重定向标准输出(见上文) 可能是一个愚蠢的问题,但你确定exec()
d 命令实际上打印了某事。到标准输出?至少你应该在printf()
之后添加一个fflush(stdout)
否则它可能只是在内部缓冲
:我什至在 exec(...) 之前做了一个 fprintf(stdout, ...) 和 fprintf(stderr, ...)。 stderr 进入文件,stdout 没有。明天我会尝试fflush,也许它会有所帮助【参考方案2】:
我现在更加简化了我的程序:
int main(int argc,
char* argv[])
pid_t pid ;
int fd = open("main.log", O_RDWR | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) ;
dup2(fd, STDERR_FILENO) ; // make stdout go to file
dup2(fd, STDOUT_FILENO) ; // make stderr go to file
close(fd) ;
fprintf(stdout, "Main: This is an output message") ;
fprintf(stderr, "Main: This is an error message") ;
fflush(stdout) ;
fflush(stderr) ;
if ((pid = fork()) == 0)
fd = open("sub.log", O_RDWR | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH) ;
dup2(fd, STDERR_FILENO) ; // make stdout go to file
dup2(fd, STDOUT_FILENO) ; // make stderr go to file
close(fd) ;
fprintf(stdout, "Sub: This is an output message") ;
fprintf(stderr, "Sub: This is an error message") ;
fflush(stdout) ;
fflush(stderr) ;
exit(0) ;
exit(EXIT_SUCCESS) ;
这给了我
::::::::::::::
main.log
::::::::::::::
Main: This is an error messageMain: This is an output message
::::::::::::::
sub.log
::::::::::::::
Sub: This is an error messageSub: This is an output message
所以,调用的进程肯定有问题。它输出到标准输出,但是当作为子进程调用时,一定有什么东西阻碍了他这样做(交互调用,标准输出上有很多输出)。 如果有人知道可能是什么原因,我将感谢您提供任何进一步的帮助。 非常感谢您到目前为止的帮助。
约尔格
【讨论】:
【参考方案3】:尤里卡,我找到了。
我们从外部供应商处调用库函数。在此调用之前,一切正常,之后,不再有输出到 stdout。
我现在联系了供应商,询问他们在那里做什么。同时,这也有帮助:
int saved_stdout = dup(STDOUT_FILENO) ;
// vendor library call
dup2(saved_stdout, STDOUT_FILENO) ;
感谢大家的帮助
祝好,周末愉快
约尔格
【讨论】:
以上是关于在C中重定向子进程的文件输出的主要内容,如果未能解决你的问题,请参考以下文章