【问题标题】:shell in C, input & pipesC语言中的shell,输入和管道
【发布时间】:2017-04-02 16:04:51
【问题描述】:

我一直在用 C 语言制作一个迷你 shell,它必须接收带有至少 3 个参数的命令,解析它们,然后应用 fork() 和 exec(),如果你只是按 Enter,它应该会再次打印提示.它还必须接受多个管道,这就是我被卡住的地方。这是我的代码

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

int main(){

char command[50];
char* token;
char* param[50][50];
int i,j,k;


 while(1){
        printf("shell:~");
        fgets(command, sizeof(command), stdin);

        i=0,j=0;                        
        token = strtok(command," \n\0\t");      
    while(1){
        if(token==NULL) break;  
        else if(strcmp(token,"|")==0){
            param[i][j]=0;
            i = i+1;
            j=0;
            token = strtok(NULL," \n\0\t");
        }
        else{
            param[i][j]=token;                      
            token = strtok(NULL," \n\0\t");
            j = j+1;
        }
        }
        param[i][j]=0;

到目前为止一切正常。

    pid_t pid1,pid2;
    int fd1[2],fd2[2];
    //int numpipe = i-1;

    pipe(fd1);
    pipe(fd2);
    int status;

    pid1 = fork();
    if(pid1==0){
        k=0;
        while(k<i+1){
            pid2 = fork();
            if(pid2==0){

                if(k==0){// if it is first
                    if(k==i){//and last one
                        execvp(param[k][0],param[k]);

                    }else{
                        dup2(fd1[1],STDOUT_FILENO);
                        close(fd1[0]);
                        execvp(param[k][0],param[k]);

                        }                       
                }else if(0<k<i){//if it is in the middle
                    if(k%2==0){ // position odd
                        dup2(fd2[0],STDIN_FILENO);
                        close(fd2[1]);
                        dup2(fd1[1],STDOUT_FILENO);
                        close(fd1[0]);
                        execvp(param[k][0],param[k]);
                    }else{ //position 
                        dup2(fd1[0],STDIN_FILENO);
                        close(fd1[1]);
                        dup2(fd2[1],STDOUT_FILENO);
                        close(fd2[0]);
                        execvp(param[k][0],param[k]);   
                    }   
                }else{//if it is lasts
                    if(k%2==0){
                        dup2(fd2[0],STDIN_FILENO);
                        close(fd2[1]);
                        execvp(param[k][0],param[k]);
                    }else{
                        dup2(fd1[1],STDIN_FILENO);
                        close(fd1[1]);
                        execvp(param[k][0],param[k]);
                    }
                }                                   
            }else{
                k++;
                wait(NULL);
            }
    }
}
    else{
        wait(NULL);
    }
}
return 0;
}

如果我只使用 1 个命令,代码效果很好,但是当我放一个管道时它没有得到输入,例如:

    shell:~ls -l
    total 112
    -rw-r--r-- 1 cristian cristian 72018 mar 28 13:25 (107315)proyecto1-SO2017-1.pdf
    -rw-rw-r-- 1 cristian cristian     0 abr  2 12:23 a.out
    -rw-rw-r-- 1 cristian cristian  1082 abr  1 23:47 reaspaldo2
    -rw-rw-r-- 1 cristian cristian  1217 abr  2 03:00 reaspaldo2.c
    -rw-rw-r-- 1 cristian cristian   962 abr  1 19:40 respaldo1
    -rw-rw-r-- 1 cristian cristian   636 abr  2 01:10 respaldo1.c
    -rwxrwxr-x 1 cristian cristian 13200 abr  2 12:35 shell
    -rw-r--r-- 1 cristian cristian  1984 abr  2 12:36 shell.c
    -rw-r--r-- 1 cristian cristian   807 mar 29 11:41 shell.c~
    shell:~ls -l | wc
    wc: 'standard input': Bad file descriptor
          0       0       0
    shell:~

它与 STDIN_FILE 相关,但我确信我没有很好地实现管道和分叉。

【问题讨论】:

  • 您没有关闭所有文件描述符。通常,您的代码应类似于 pipe(fd); if(fork()==0) {close(fd[0]); dup2(fd[1],STDOUT_FILENO); close(fd[1])
  • 是的,我也试过了,但是效果一样,就像 excvp() 没有从管道中获取参数
  • 一次解决一个问题。您根本没有关闭父级中的任何文件描述符!但更直接的问题是dup2(fd1[1],STDIN_FILENO);fd[1] 是管道的写入端,应该写入。尝试从中读取将产生您所看到的错误。

标签: c shell pipe fork


【解决方案1】:

将您的问题减少到最小的可重现案例:

#include <unistd.h>
#include <stdio.h>

int main(void) 
{
        char *argv[] = {"wc", NULL};
        int fd1[2];
        pipe(fd1);
        dup2(fd1[1],STDIN_FILENO); /* Wrong end of the pipe !! */
        close(fd1[1]);
        execvp(argv[0], argv);
        perror(argv[0]);
        return 1;
}

问题是fd1[1] 是管道的写入端,但wc 正在尝试从中读取。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 2015-08-19
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 2021-04-03
    • 1970-01-01
    相关资源
    最近更新 更多