【问题标题】:Recursive piping in Unix again再次在 Unix 中进行递归管道
【发布时间】:2014-01-23 11:35:31
【问题描述】:

我知道这个话题已经出现了好几次,但我仍然停留在某一点上。 我需要编写一个模拟cmd1 | cmd2 | cmd3 ... 管道的程序。

我的代码在这里:http://ideone.com/fedrB8

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>

void pipeline( char * ar[], int pos, int in_fd);
void error_exit(const char*);
static int child = 0; /* whether it is a child process relative to main() */

int main(int argc, char * argv[]) {
    if(argc < 2){
        printf("Usage: %s option (option) ...\n", argv[0]);
        exit(1);
    }
    pipeline(argv, 1, STDIN_FILENO);
    return 0;
}

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

void pipeline(char *ar[], int pos, int in_fd){
    if(ar[pos+1] == NULL){ /*last command */
        if(in_fd != STDIN_FILENO){
            if(dup2(in_fd, STDIN_FILENO) != -1)
                close(in_fd); /*successfully redirected*/
            else error_exit("dup2");
        }
        execlp(ar[pos], ar[pos], NULL);
        error_exit("execlp last");
    }
    else{
        int fd[2];
        pid_t childpid;

        if ((pipe(fd) == -1) || ((childpid = fork()) == -1)) {
            error_exit("Failed to setup pipeline");
        }
        if (childpid == 0){ /* child executes current command */
            child = 1;
            close(fd[0]);
            if (dup2(in_fd, STDIN_FILENO) == -1) /*read from in_fd */
                perror("Failed to redirect stdin");
            if (dup2(fd[1], STDOUT_FILENO) == -1)   /*write to fd[1]*/
                perror("Failed to redirect stdout");
            else if ((close(fd[1]) == -1) || (close(in_fd) == - 1))
                perror("Failed to close extra pipe descriptors");
            else {
                execlp(ar[pos], ar[pos], NULL);
                error_exit("Failed to execlp");
            }
        }
        close(fd[1]);   /* parent executes the rest of commands */
        close(in_fd);
        pipeline(ar, pos+1, fd[0]);
    }
}

它最多可以处理 3 个命令,但当涉及到 4 个或更多命令时,它就不再工作了,经过数小时的分析,我仍然无法找到问题所在。

Example: 
./prog ls uniq sort head 

gives: 
sort: stat failed: -: Bad file descriptor

【问题讨论】:

  • 在“真实”情况下,您最后的if-clause (childpid == 0) 会发生什么?该子句之后的最后三行不应该在 else 块内吗?
  • krlmlr: 之前是我的想法,在 else 块中使用后没有任何改变

标签: c linux pipeline


【解决方案1】:

不是专家,但似乎以下行是问题所在:

((close(fd[1]) == -1) || (close(in_fd) == - 1))

尽量不要在那里关闭in_fd

我认为,父母正试图关闭被孩子关闭的同一个 fd。
当您使用dup2() 时,您不需要关闭文件,因为dup2() 已经关闭了文件。

【讨论】:

  • 我能够复制@Mia 的问题并成功应用此建议。
  • follow-up question 来到这里,我不明白一件事:我在man 页面中找不到dup2() 关闭first i> 论据;它确实会尝试关闭第二个,即STDOUT_FILENOSTDIN_FILENOfd[1]in_fd 应该仍处于打开状态。手册页部分:“int dup2(int oldfd, int newfd); [...] dup2() 使 newfd 成为 oldfd 的副本,必要时先关闭 newfd ...”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-11
  • 2019-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多