再次在Unix中进行递归管道第2部分

时间:2018-12-04 08:00:34

标签: c shell recursion pipe file-descriptor

我知道这个话题已经发布了很多,但我希望将其转向另一个方向。我想编写一个具有外壳管道功能的程序,即cmd1 | cmd2 | cmd3管道和重定向。我已阅读thisthisthis之类的页面作为参考。这些解决方案对于“水平流水线”非常有用,但是我想“垂直”实现它。为了使我的外壳垂直,每个“命令”进程必须具有不同的父项(上一个命令)。因此,每个要执行的命令都是从前一个命令生成的。我遇到的问题是,当我递归子对象(而不是像示例那样的父对象)时,程序执行正常,但随后挂起,我必须按Enter键才能提示我的shell。我很好奇为什么这有所不同以及如何解决。

static void exec_pipeline(size_t pos, int in_fd) {
    // Invalid Pipe has issues
    if (newargv[pipe_commands[pos+1]] == NULL)
        report_error_and_exit("Invalid pipe");
/* last command, pipe_command conatins indices of commands to execute */
    if (pipe_commands[pos + 1] == 0) { 
        redirect(in_fd, STDIN_FILENO); /* read from in_fd, write to STDOUT */
        execvp(newargv[pipe_commands[pos]], newargv + pipe_commands[pos]);
        report_error_and_exit("execvp last command");
    }
    else { /* $ <in_fd cmds[pos] >fd[1] | <fd[0] cmds[pos+1] ... */
        int fd[2]; /* output pipe */
        if (pipe(fd) == -1)
            report_error_and_exit("pipe");
        switch(fork()) {
            case -1:
                report_error_and_exit("fork");
            case 0: /* parent: execute the rest of the commands */
                CHK(close(fd[1])); /* unused */
                CHK(close(in_fd)); /* unused */
                exec_pipeline(pos + 1, fd[0]); /* execute the rest */
            default: /* child: execute current command `cmds[pos]` */
                child = 1;
                CHK(close(fd[0])); /* unused */
                redirect(in_fd, STDIN_FILENO);  /* read from in_fd */
                redirect(fd[1], STDOUT_FILENO); /* write to fd[1] */
                execvp(newargv[pipe_commands[pos]], newargv + pipe_commands[pos]);
                report_error_and_exit("execvp");

        }
    }
}
void report_error_and_exit(const char *msg) {
    perror(msg);
    (child ? _exit : exit)(EXIT_FAILURE);
}

/* move oldfd to newfd */
void redirect(int oldfd, int newfd) {
    if (oldfd != newfd) {
        if (dup2(oldfd, newfd) != -1)
            CHK(close(oldfd));
        else
            report_error_and_exit("dup2");
    }
}

CHK非常类似于assert,在一个名为CHK.h的文件中定义,如果您好奇的话,它看起来像这样:

  do {if((x) == -1)\
   {fprintf(stderr,"In file %s, on line %d:\n",__FILE__,__LINE__);\
    fprintf(stderr,"errno = %d\n",errno);\
    perror("Exiting because");\
    exit(1);\
   }\
 } while(0)

1 个答案:

答案 0 :(得分:0)

想通了!因此,问题在于使用垂直实现时,要执行的最后一条命令是“ cmd3”,而该命令本来应该是“ cmd1”。不是一个完美的解决方案,但可以。基本上只是反转了管道的构建方向。但是,此解决方案仍然存在一些文件描述符问题,这些问题与传入的输入有关。

exec 88<>/dev/tcp/rssweather.com/80
echo -e "GET /dir/Asia/India HTTP/1.1\nhost: www.rssweather.com\nConnection: close\n\n" >&88
sed 's/<[^>]*>/ /g' <&88