2009-11-07 4 views
9

J'essaie de créer un shell simple en C pour Unix. J'ai été capable de faire tout l'analyse des commandes et de l'exécution, mais j'ai un problème avec la tuyauterie. Je pense que le problème est que je ne suis pas accroché dans le bon tuyau pour l'entrée de la deuxième commande. Par exemple, si je tape "ls | wc", il s'arrêtera après la commande "wc", ce qui est dû au fait qu'il attend l'entrée. Je pense que le problème est quand j'utilise dup2 (en lisant [i], 0), et son ne pas accrocher dans le bon tuyau. Je sais que c'est un peu une question générale, mais s'il y a des pointeurs que je pourrais obtenir, j'apprécierais. Voici le code qui crée de nouveaux processus et essaie de les canaliser.Problème avec les commandes de tuyauterie en C

int fileds[2]; 
    int reading[num_cmds]; 
    int writing[num_cmds]; 

    int p; 
    for(p=0; p < num_cmds; p++) 
    { 
     reading[p] = -1; 
     writing[p] = -1; 
    } 

    int j; 
    for(j=0; j < num_cmds-1; j++) //Create pipes for commands 
    { 
     int fileds[2]; 
     pipe(fileds); 
     reading[j+1] = fileds[0]; 
     writing[j] = fileds[1]; 
    } 

    int i = 0; 
    for(i = 0; i < num_cmds;i++) 
    {   
     cmd_args = parse_cmd(cmds[i],output_file,input_file,&run_bg); //Get command and args 

     pid_t childpid; 
     int status; 
     childpid=fork(); 

     if (childpid >= 0) 
     { 
      if (childpid == 0) 
      {    
       if(writing[i] != -1) 
       { 
        dup2(writing[i],1); 
        close(writing[i]); 
       } 

       if(reading[i] != -1) 
       { 
        dup2(reading[i],0); 
        close(reading[i]); 
       } 

       int h; 
       for(h = 0; h < num_cmds; h++) 
       { 
        close(writing[h]); 
        close(reading[h]); 
       } 

       if(execvp(cmd_args[0],cmd_args) == -1) 
       { 
        perror("Problem with command"); 
        exit(0); 
       } 
      } 
      else 
      { 
       wait(&status); 
       int m; 
       for(m = 0; m < num_cmds; m++) 
       { 
        if(writing[m] != -1) close(writing[m]); 
        if(reading[m] != -1) close(reading[m]); 
       } 
      } 
     } 
     else 
     { 
      perror("fork"); 
      continue; 
     } 


     input_file[0] = 0; 
     output_file[0] = 0; 
     run_bg = 0; 
    } 

} 



MISE À JOUR: J'ai pu comprendre, grâce à Richard. C'était une combinaison de fermer les descripteurs de dossier dans le mauvais ordre et de ne pas en fermer du tout. Voici le code de travail.

int fileds[2]; 
    int reading[num_cmds]; 
    int writing[num_cmds]; 

    int p; 
    for(p=0; p < num_cmds; p++) 
    { 
     reading[p] = -1; 
     writing[p] = -1; 
    } 

    int j; 
    for(j=0; j < num_cmds-1; j++) 
    { 
     int fileds[2]; 
     pipe(fileds); 
     reading[j+1] = fileds[0]; 
     writing[j] = fileds[1]; 
    } 

    int i = 0; 
    for(i = 0; i < num_cmds;i++) 
    {   
     cmd_args = parse_cmd(cmds[i],output_file,input_file,&run_bg); 

     pid_t childpid; 
     int status; 
     childpid=fork(); 

     if (childpid >= 0) 
     { 
      if (childpid == 0) 
      {    
       if(writing[i] != -1) 
       { 
        close(1); 
        dup2(writing[i],1); 
       } 

       if(reading[i] != -1) 
       { 
        close(0); 
        dup2(reading[i],0); 
       } 

       if(execvp(cmd_args[0],cmd_args) == -1) 
       { 
        perror("Problem with command"); 
        exit(0); 
       } 
      } 
      else 
      { 

       wait(&status); 
       close(writing[i]); 

       if(i > 0) 
       { 
        close(reading[i]); 
       } 
      } 
     } 
     else 
     { 
      perror("fork"); 
     } 


     input_file[0] = 0; 
     output_file[0] = 0; 
     run_bg = 0; 
    } 

Répondre

2

Je pense que votre problème est peut-être que vous attendez chaque processus à l'intérieur de la boucle, puis fermez tous les descripteurs de fichier. Cela rend les descripteurs de fichiers invalides pour l'appel suivant à dup2() et aboutit à stdin pour le processus suivant restant inchangé.

Juste une supposition, je n'ai pas exécuté le code.

+0

Je pense que vous avez raison. J'ai essayé de commenter la fermeture de if (reading [m]! = -1) (en lisant [m]); dans la boucle, et cela me permet de canaliser 2 commandes. Merci de m'indiquer dans la bonne direction! – mbxtr

0

Lorsque je tape « ls | wc » wc fait comme prévu et affiche le nombre de sortie de mots par la commande ls. Rappelez-vous que lorsque vous utilisez des commandes "|" vous n'avez pas besoin de créer des tuyaux dans votre application. La première commande doit sortir vers stdout et la deuxième commande doit lire cette sortie depuis l'entrée standard.

+0

Il s'agit d'un projet visant à comprendre le fonctionnement de la tuyauterie. Je dois donc pouvoir configurer la tuyauterie. "ls | wc" fonctionne dans un terminal normal, mais je dois l'imiter dans ce programme. D'après ce que je comprends, je dois définir la sortie de la première commande - "ls" dans ce cas pour être la sortie du tuyau, et l'entrée de la deuxième commande, pour être l'entrée du tuyau. – mbxtr

+0

Eh bien, si vous implémentez un shell pour fournir ce mécanisme de tuyauterie, vous devez utiliser des tuyaux ou un mécanisme similaire. Je pense que le demandeur connaît ces problèmes; il demande pourquoi cela ne fonctionne pas. – BobbyShaftoe