C shell中的多个管道

Posted

技术标签:

【中文标题】C shell中的多个管道【英文标题】:multiple piping in C shell 【发布时间】:2014-12-01 07:42:07 【问题描述】:

谁能告诉我这段代码有什么问题。当我将该管道输出端用作另一个命令的输入时,我能够成功地写入管道,但无法获得输出。下面是代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>     //for pid_t fork() and other system calls
#include <signal.h>     //for signal()
#include <sys/types.h>


void command_EXECUTER(char *args[]);
void command_HANDLER(char *args[]);
int pipe_EXECUTER(char *args[], int in, int pos);

void shell_INIT()

    int is_interactive = isatty(STDOUT_FILENO);

    if(is_interactive)



    



int main(int argc, char *argv[], char **envp)

    char shell_INPUT[1024];
    char *tokens[256];
    int tok_counts = 0;

    while(1)

        memset(shell_INPUT,'\0',sizeof(shell_INPUT));

        printf("\n%s@%s: ",getenv("USER"),getenv("SESSION"));
        fgets(shell_INPUT,1024,stdin);

        if((tokens[0] = strtok(shell_INPUT," \n)\t")) == NULL) continue;

        tok_counts = 1;

        while((tokens[tok_counts] = strtok(NULL, " \n\t")) != NULL) tok_counts++;
        /*
        int i=0;
        while(tokens[i])
            printf("%s ",tokens[i]);
            i++;
        
        tokens[tok_counts] = NULL;*/
        command_HANDLER(tokens);

    


    return 0;


int fileIO_EXECUTER(char *args[], int in, int pos)
    int fd;
    pid_t pid;

    if((pid=fork())==0)
        switch(pos)

            case 0: 
                    dup2(fd, STDOUT_FILENO);
                    break;


        
    


int pipe_EXECUTER(char *args[], int in, int pos)

    int fd[2];
    pid_t pid;
    pipe(fd);

    if((pid=fork())==0)
        printf("%s %s %s %d\n",args[0],args[1],args[2],pid);
        fflush(stdout);
        switch(pos)

            case 0: dup2(fd[1], STDOUT_FILENO);     //first command
                    //close(fd[1]);
                    break;

            case 1: dup2(in, STDIN_FILENO);             //in between command
                    dup2(fd[1], STDOUT_FILENO);
                    //close(fd[1]);
                    break;

            case 2: dup2(in, STDIN_FILENO);         //last command
                    //close(fd[1]);
                    break;

            default: printf("wrong input variable\nexiting");
                     exit(1);   

        
        if(execvp(args[0],args)==-1) printf("%s: command not found",args[0]); fflush(stdout); kill(getpid(),SIGTERM);

    else if(pid<0)
        printf("couldn't create child");
        exit(1);
    else
        wait(pid);
    

    return fd[0];



void command_EXECUTER(char *args[])

    pid_t pid;

    if((pid=fork())<0)
        printf("couldn't create the child");
        exit(1);
    
    else if(pid==0)

        if((execvp(args[0],args))==-1) printf("%s: command not found",args[0]); fflush(stdout); kill(getpid(),SIGTERM);
    
    else wait(pid);



void command_HANDLER(char *args[])

    int i=0;
    int j=0;
    char spec_chars[100];

    while(args[i])
        if((strcmp(args[i],">")==0) || (strcmp(args[i],"<")==0) || (strcmp(args[i],"|")==0) || (strcmp(args[i],"&")==0) || (strcmp(args[i],"$")==0))
            spec_chars[j] = *args[i];
            j++;
        
        i++;
    

    if(j==0)
        if(strcmp(args[0],"exit")==0) exit(0);
        else if(strcmp(args[0],"clear")==0) system("clear");
        else command_EXECUTER(args);
    
    else

        int in = 0;
        int h = 0;
        int pos=0;
        char data[1024];
        int k=i;
        i = 0;
        while(args[i])
            if(strcmp(args[i],"|")==0)
                args[i] = (char *)NULL;
                in = pipe_EXECUTER(args,in,pos);
                int n = read(in,data,sizeof(data));
                printf("%s %d\n",data,n);
                fflush(stdout);
                args = args+i+1;

                //printf("%s something %s",args[0],args[1]);
                pos = 1;
                i=0;
            else if(strcmp(args[i],"<")==0)


            else if(strcmp(args[i],">")==0)

            else if(strcmp(args[i],"&")==0)

            
            else
                i++;
            

        
        in = pipe_EXECUTER(args,in,2);
    


例如,如果我使用

ls |排序

'in' 描述符里面会有 ls 但是 当'sort'访问相同的输出时,它会挂在那里......或者执行该命令的子进程永远不会死,并且由于这个父进程一直在等待。

【问题讨论】:

请编译所有警告和调试信息 (gcc -Wall -Wextra -g) 然后使用调试器 (gdb);还针对每个syscalls(2) 测试失败(并在失败时使用perror)。也可以考虑使用strace & valgrind 其实我才刚开始,不知道如何使用gdb或其他调试工具..如果你能帮忙..谢谢 不,你需要学习gdb。这是一项可以使用多年的技能!阅读GDB documentation 嘿,@BasileStarynkevitch 我研究并尝试了所有 gdb、strace 和 valgrind,但仍然没有运气:( 一些错误需要数周才能被发现。祝你好运!不要放弃。休息一下,然后继续寻找你的错误。不要忘记阅读您正在使用的每个系统调用的文档。特别是,您对dup2 的使用是错误的:您没有处理dup2 的失败。另外,请在fork 之前致电fflush 【参考方案1】:

'in' 描述符将在其中包含 ls 但是当相同的输出是 通过“排序”访问它挂在那里

这是由于在父进程中没有关闭管道的写端的疏忽造成的,因为sort自然会等到所有文件描述符引用写端关闭,确保不再有输入到达。因此,在pipe_EXECUTER() 中,您必须先调用close(fd[1]),然后再调用return fd[0];,当然还有调试代码

                int n = read(in,data,sizeof(data));
                printf("%s %d\n",data,n);

必须删除command_HANDLER() 中的内容,以免消耗sort 的输入。

【讨论】:

以上是关于C shell中的多个管道的主要内容,如果未能解决你的问题,请参考以下文章

C++ Shell 多管道不工作?

协调/控制多个 C 应用程序

无法将多个 shell 语句重定向到命名管道

如何从在 C 中存储 shell 脚本输出的指针获取多个字符串?

shell 管道命令与过滤器

24 shell 管道命令与过滤器