使用execvp时输入重定向问题?

时间:2011-04-10 06:38:07

标签: c fork redirect

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

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

任何解决此问题的方法。 Plz批评我的代码也是..

谢谢

 /* 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) ); */

    }
}

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

您的代码不符合您的描述:

你创建一个管道,分叉一个新进程,将它的stdout重定向到管道并让它执行一些程序(到目前为止一直这么好),然后在父进程中等待你的孩子完成,然后才分叉第二个进程,将它的stdin重定向到另一端的管道,并让它执行另一个程序。

这不是“ls | wc”的作用 - 在shell中它们同时运行。删除第一个wait()。

答案 2 :(得分:1)

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,因为您可能会意外收获另一个子流程。)

相关问题