Linux shell 中的管道函数用 C 编写 [英] Pipe function in Linux shell write in C

查看:78
本文介绍了Linux shell 中的管道函数用 C 编写的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的小shell程序接受管道命令,例如,ls -l |wc -l 并使用 excevp 来执行这些命令.

My mini-shell program accepts pipe command, for example, ls -l | wc -l and uses excevp to execute these commands.

我的问题是,如果 execvp 没有 fork(),管道命令运行良好,但 shell 之后终止.如果execvp 有fork(),就会发生死循环.我无法修复它.

My problem is if there is no fork() for execvp, the pipe command works well but the shell terminates afterward. If there is a fork() for execvp, dead loop happens. And I cannot fix it.

代码:

void run_pipe(char **args){
    int ps[2];
    pipe(ps);

    pid_t pid = fork();
    pid_t child_pid;
    int child_status;

    if(pid == 0){ // child process

        close(1);
        close(ps[0]);
        dup2(ps[1], 1);

       //e.g. cmd[0] = "ls", cmd[1] = "-l"
        char ** cmd = split(args[index], " \t");   

        //if fork here, program cannot continue with infinite loop somewhere
        if(fork()==0){
            if (execvp(cmd[0],cmd)==-1){
                printf("%s: Command not found.\n", args[0]);
            }
        }
        wait(0);
    }
    else{ // parent process

        close(0);
        close(ps[1]);
        dup2(ps[0],0);

        //e.g. cmd[0] = "wc", cmd[1] = "-l"
        char ** cmd = split(args[index+1], " \t");

        //if fork here, program cannot continue with infinite loop somewhere
        if(fork()==0){
           if (execvp(cmd[0],cmd)==-1){
                printf("%s: Command not found.\n", args[0]);
           }
        }
        wait(0);
        waitpid(pid, &child_status, 0);
    }    
 }

我知道 excevp 需要 fork() 才能不终止 shell 程序,但我仍然无法修复它.任何帮助将不胜感激,谢谢!

I know fork() is needed for excevp in order to not terminate the shell program, but I still cannot fix it. Any help will be appreciated, thank you!

我应该如何让两个孩子平行?

How should I make two children parallel?

pid = fork(); 
if( pid == 0){ 
    // child 
} else{ // parent 
    pid1 = fork(); 
if(pid1 == 0){ 
    // second child 
} else // parent 

} 

这是正确的吗?

推荐答案

是的,execvp() 用不同的程序替换调用它的程序.如果您想生成另一个程序而不结束生成生成的程序(即 shell)的执行,那么该程序必须 fork() 来创建一个新进程,并让新进程执行 <代码>execvp().

Yes, execvp() replaces the program in which it is called with a different one. If you want to spawn another program without ending execution of the one that does the spawning (i.e. a shell) then that program must fork() to create a new process, and have the new process perform the execvp().

您的程序源表现出错误的并行性,这可能会让您感到困惑或反映出更深层次的困惑.您以与 fork 之后父进程的行为相同的方式构建第一个子进程的行为,但是应该并行的是第一个子进程的行为和第二个子进程的行为孩子.

Your program source exhibits a false parallelism that probably either confuses you or reflects a deeper confusion. You structure the behavior of the first child forked in just the same way as the behavior of the parent process after the fork, but what should be parallel is the behavior of the first child and the behavior of the second child.

一个结果是你的程序有太多的分叉.初始进程应该分叉两次——每个它想要生成的子进程一次——并且两个子进程都不应该分叉,因为它已经是一个专用于您要运行的命令之一的进程.但是,在您的实际程序中,第一个孩子确实分叉了.那个案例可能是由孩子也为孙子wait()拯救了,但它是凌乱和糟糕的形式.

One outcome is that your program has too many forks. The initial process should fork exactly twice -- once for each child it wants to spawn -- and neither child should fork because it's already a process dedicated to one of the commands you want to run. In your actual program, however, the first child does fork. That case is probably rescued by the child also wait()ing for the grandchild, but it's messy and poor form.

另一个结果是,当您设置第二个孩子的文件描述符时,您在分叉之前操作父的,而不是分叉后操作孩子的.这些更改将保留在父进程中,我非常有信心这不是您想要的.这可能就是 shell 似乎挂起的原因:当 run_pipe() 返回时(shell 的标准输入已更改为管道的读取端).

Another outcome is that when you set up the second child's file descriptors, you manipulate the parent's, prior to forking, instead of manipulating the child's after forking. Those changes will persist in the parent process, which I'm pretty confident is not what you want. This is probably why the shell seems to hang: when run_pipe() returns (the shell's standard input has been changed to the read end of the pipe).

此外,父进程应该在子进程都被派生后关闭管道的两端,这或多或少的原因是子进程必须各自关闭他们不使用的一端.最后,管道的每一端都会有一个文件描述符的打开副本,一个在一个子节点中,另一个在另一个子节点中.在某些情况下,未能正确执行此操作也可能导致挂起,因为您 fork 的进程可能不会终止.

Additionally, the parent process should close both ends of the pipe after the children have both been forked, for more or less the same reason that the children must each close the end they are not using. In the end, there will be exactly one open copy of the file descriptor for each end of the pipe, one in one child and the other in the other. Failing to do this correctly can also cause a hang under some circumstances, as the processes you fork may not terminate.

以下是您希望程序执行的操作的摘要:

Here's a summary of what you want the program to do:

  • 原始进程设置管道.
  • 原始进程 fork 两次,每个命令一次.
  • 每个子进程操作自己的文件描述符,将管道的正确一端用作适当的标准 FD,并关闭管道的另一端.
  • 每个子进程使用 execvp()(或该系列中的其他函数之一)来运行请求的程序
  • 父进程关闭管道两端的文件描述符副本
  • 父级使用 wait()waitpid() 来收集两个子级.
  • The original process sets up the pipe.
  • The original process forks twice, once for each command.
  • Each subprocess manipulates its own file descriptors to use the correct end of the pipe as the appropriate standard FD, and closes the other end of the pipe.
  • Each subprocess uses execvp() (or one of the other functions in that family) to run the requested program
  • the parent closes its copies of the file descriptors for both ends of the pipe
  • the parent uses wait() or waitpid() to collect two children.

还要注意,您应该检查所有函数调用的返回值并提供适当的错误处理.

这篇关于Linux shell 中的管道函数用 C 编写的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆