2017-04-02 6 views
0

Ich habe eine Mini-Shell in C gemacht, die Befehle mit mindestens 3 Argumente erhalten muss, Parsing sie, dann anwenden fork() und exec(), wenn Sie nur die Eingabetaste drücken Es sollte die Aufforderung erneut drucken. Auch muss es mehrere Rohre akzeptieren, das ist wo ich stecken geblieben bin. Das ist mein CodeShell in C, Eingabe & Pipes

#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; 

Alles funktioniert gut bis hier.

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; 
} 

Der Code funktioniert gut, wenn ich nur 1 Befehl zu verwenden, aber wenn ich ein Rohr setzen tut es den Eingang zu erhalten, zum Beispiel:

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:~ 

Sein zum STDIN_FILE verwendet, aber auch ich Ich bin mir sicher, dass ich die Rohre und die Gabeln nicht gut umsetzen kann.

+0

Sie schließen nicht alle Ihre Dateideskriptoren. Normalerweise sollte Ihr Code wie folgt aussehen: 'pipe (fd); if (fork() == 0) {schließen (fd [0]); dup2 (fd [1], STDOUT_FILENO); close (fd [1]) ' –

+0

yeah, das habe ich auch schon ausprobiert, aber es tut das gleiche, ist wie die excvp() bekommt nicht die Argumente aus der Pipe –

+0

Fix ein Problem zu einer Zeit. Sie schließen keine Dateideskriptoren im übergeordneten Element überhaupt! Aber das unmittelbare Problem ist 'dup2 (fd1 [1], STDIN_FILENO);'. 'fd [1]' ist die Schreibseite der Pipe und sollte in geschrieben werden. Wenn Sie versuchen, davon zu lesen, wird der angezeigte Fehler generiert. –

Antwort

0

Reduzierung Ihres Problems auf einen minimalen reproduzierbaren Fall:

#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; 
} 

Das Problem ist, dass fd1[1] die Schreibseite eines Rohres, aber wc versucht, sich von ihm zu lesen.