【问题标题】:Input redirection problem while using execvp?使用 execvp 时出现输入重定向问题?
【发布时间】:2011-04-10 06:38:06
【问题描述】:

我已经实现了一个简单的程序,它使用简单的管道和 execvp 调用来模拟 $ls -l | wc -c 命令的执行。

现在重定向stdin和stdout后,当执行程序时,shell提示符消失,等待回车键被按下。

解决这个问题的任何方法。也请批评我的代码..

谢谢

 /* Create pipe */
  ret_val=pipe(pipe_fd);
  /*Error check */
   if(ERROR==ret_val)
   {
    perror("Pipe creation error \n");
    _exit(FAILURE);
   }

/*Fork First Child */
pid_one = fork() ;

if( 0 == pid_one ) /*child process block */
{


    /* First sub process */
    /*printf("First sub process is %d \n",getpid());*/

    /* redirect stdout to pipe's write end  for sub process one*/
    dup2(pipe_fd[1],1);


    /*close pipe read end */
    close(pipe_fd[0]);

    execvp(cmd_one_tokens[0],cmd_one_tokens);   

    /* if execvp returns then if must have failed */
    printf("Unknown Command \n ");
    //exit(10);
}
else /*main process block */
{
    /*printf(" Main  process is %d \n",getpid());*/

    /*Wait for first sub process to finish */
    //wait(&status);

    /*printf("Exit status of first child is %d \n ", WEXITSTATUS(status) );*/

    /*Fork second subprocess */
    pid_two = fork();

    if( 0 == pid_two ) /*second child process block */
    {
        /* redirect stdin  to pipe's read end  for sub process two */
        dup2(pipe_fd[0],0);

    //  close(0);       /* close normal stdin */
        //  dup(pipe_fd[0]);   /* make stdib same as pfds[0] */


        /*close pipe write end */
        close(pipe_fd[1]);

        /* Second  sub process */
        /*printf("Second sub process is %d \n",getpid()); */

        execvp(cmd_two_tokens[0] , cmd_two_tokens); 
        /* if execvp returns then if must have failed */
        printf("Unknown Command \n ");

    }
    else        /*main process block */
    {
        /* printf(" Main  process is %d \n",getpid()); */
        status=-1; /*reset status */

        /*Waiting for the second sub process to finish in No hang fashion */
            waitpid ( -1 , &status ,WNOHANG);
        /*printf("Exit status of second  child is %d \n ", WEXITSTATUS(status) ); */

    }
}

【问题讨论】:

    标签: c fork redirect


    【解决方案1】:

    在第二个被分叉之后,您必须在主进程中关闭管道文件描述符。在您关闭它们之前,子进程 (wc) 将等待主进程仍然打开的管道上的输入。您必须非常小心地关闭管道的所有不需要的末端。

    【讨论】:

      【解决方案2】:

      你的代码没有按照你描述的那样做:

      你创建一个管道,派生一个新进程,将它的标准输出重定向到管道并让它执行一些程序(到目前为止一切都很好),然后在父进程中等待你的孩子完成,然后再派生第二个进程, 把它的标准输入重定向到管道的另一端,让它执行另一个程序。

      这不是 "ls | wc" 所做的——在它们同时运行的 shell 中。删除第一个 wait()。

      【讨论】:

      • 好的,我已经改了。您能否为该提示问题提供任何建议....
      • 只是一个猜测,但我会在程序结束时尝试 fflush(NULL)。
      【解决方案3】:
      pid_one = fork() ;
      if( 0 == pid_one ) /*child process block */
      

      您没有检查fork(2) 是否有错误返回,这是非常可能的。 (用户可能会遇到RLIMIT_NPROC 限制、kernel.threads-max、用于保存任务结构的内存不足等)

      fork(2) 的更多惯用用法如下所示:

      if(-1 == (pid = fork()) {
          perror("fork");
          exit(1); /* or return -1 or similar */
      } else if (0 == pid) {
          /* executing as child */
      } else {
          /* parent, pid is child */
      }
      
      execvp(cmd_two_tokens[0] , cmd_two_tokens); 
      /* if execvp returns then if must have failed */
      printf("Unknown Command \n ");
      

      请注意,execvp(3) 失败的原因有很多;简单地打印“未知命令”可能会让您的用户在未来非常感到困惑。最好致电perror("execvp");,让您的用户有机会发现他们的execvp(3) 呼叫失败的真实原因。

       waitpid ( -1 , &status ,WNOHANG);
      

      在这里使用WNOHANG 可能很危险;如果系统运行“恰到好处”,您的父母可能会在孩子甚至有机会开始执行之前获得此代码。因为您已经要求它在没有孩子退出的情况下立即返回,所以当孩子最终退出时,它可能会变成僵尸——您的代码不会再次借此机会等待孩子。

      我不确定最好的解决方案是什么:如果您使用 SA_NOCLDWAITsigaction(2) 来完全避免创建僵尸,您将没有机会收集孩子的退出状态。安装SIGCHLD 信号处理程序可能会干扰进程的其余部分;您的客户可能有理由自行设置。使用阻塞 waitpid(2) 可能会在其他地方停止处理。并且使用非阻塞waitpid(2) 意味着您仍然必须有时收集孩子的状态,可能通过轮询。 (但在这种情况下,您不能将-1 用于pid,因为您可能会意外收获另一个子进程。)

      【讨论】:

        猜你喜欢
        • 2018-03-20
        • 2014-06-12
        • 2011-02-27
        • 2011-07-10
        • 1970-01-01
        • 2020-08-08
        • 2014-02-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多