在C中重定向子进程的文件输出

时间:2016-03-03 15:35:17

标签: c io-redirection

我要么完全忘记了我想知道的关于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,“这是一条消息”);),但这并没有出现在任何地方。 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) ;

- &GT;发送到stderr的消息写入文件,不是stdout

dup2(fd, STDOUT_FILENO) ;

- &GT;发送到stderr的消息写在终端,到stdout无处

dup2(fd, STDOUT_FILENO) ;
dup2(STDERR_FILENO, STDOUT_FILENO) ;

- &GT;发送到stderr的消息写入文件,发送到终端上的stdout

dup2(fd, STDERR_FILENO) ;
dup2(STDOUT_FILENO, STDERR_FILENO) ;

- &GT;发送到stderr的消息写入文件,发送到终端上的stdout

- &GT; stdout似乎有些问题!

3 个答案:

答案 0 :(得分:0)

我认为你在打开()&#34;之后立即检测到fd == 1&#34;你几乎已经回答了这个问题。根据{{​​3}}:

  

dup2()系统调用执行与dup()相同的任务,而是执行相同的任务          使用编号最小的未使用文件描述符,它使用          newfd中指定的描述符号。如果描述符newfd是          以前打开,在重新使用之前它会默默关闭。

因此,如果fd == 1并且您调用dup2( fd, STDOUT_FILENO );,那么STDOUT_FILENO(也是1)将被关闭,重定向文件的描述符也是如此。如果您无法在程序环境中找到为什么标准输出关闭,那么您可以在致电dup2()之前进行测试:

if( fd != STDOUT_FILENO )
    dup2( fp, STDOUT_FILENO );

至少那应该是一个检查我是否正确的技巧。

答案 1 :(得分:0)

我现在更加重视我的计划:

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

因此,调用过程中肯定存在问题。它输出到stdout,但是当作为子进程调用时,必须有一些阻碍他这样做的东西(交互式调用,stdout上有很多输出)。 如果有人知道可能是什么原因,我会感谢任何进一步的帮助。 非常感谢你们的帮助。

约克

答案 2 :(得分:0)

尤里卡,我找到了。

我们从外部供应商处调用库函数。在此调用之前,一切正常,之后, stdout 不再输出。

我现在联系供应商询问他们在那里做了什么。同时,这有助于:

int saved_stdout = dup(STDOUT_FILENO) ;
// vendor library call
dup2(saved_stdout, STDOUT_FILENO) ;

感谢大家的帮助

祝福,周末愉快

约克