2017-10-12 18 views
2

Mon shell C peut gérer avec succès la redirection (par exemple, ls -al> output.txt, ./pre < input1.txt, etc.) et plusieurs tuyaux (ie cmd1 | cmd 2 | cmd 3). Toutefois, mon code ne fonctionne pas lorsque j'essaie de faire une redirection d'entrée et de sortie avec un canal, par exemple ./pre < input.txt | ./sort> output.txt. Aucun fichier de sortie n'est jamais créé, bien que le ./pre soit exécuté avec succès.C Shell: redirection et piping fonctionnant, mais pas une combinaison de redirection d'entrée et de sortie avec 1 ou plusieurs canaux

avant est un exécutable qui affiche les noms avec plus de 3,0 GPAs

tri est un exécutable qui alphabetizes une liste de noms input.txt est un fichier avec les noms et GPAs (Nom 3.1 ...).

CODE:

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

#ifndef READ 
#define READ 0 
#endif 

#ifndef WRITE 
#define WRITE 1 
#endif 

void clearArgumentContainer (int argumentContainer[]); 

int main() { 
    /* professor-supplied variables for commands and command parsing */ 
    char *iPath, *oPath, *argv[20], buf[80], n, *p; 
    int m, status, inword, continu; 

    int start[20]; 

    /* flags for redirection (note: C does not have type bool; using integer value 0 or 1) */ 
    int inputRedirectFlag, outputRedirectFlag; 

    /* variables for piping */ 
    int count, pipes; 
    pid_t pid; 

    /* pipes */ 
    int l_pipe[2], r_pipe[2]; 

    /* required container for handling arguments */ 
    int argumentContainer[20] = { 0 }; 

    while (1) { 

     inword = m = continu = count = pipes = pid = 0; 

     p = buf; 

     /* redirection flags reset */ 
     inputRedirectFlag = outputRedirectFlag = 0; 

     /* shell prompt */ 
     printf("\nshhh> "); 

     /* command parsing */ 
     while ((n = getchar()) != '\n' || continu) 
     { 
      if (n == ' ') { 
       if (inword) 
       { 
        inword = 0; 
        *p++ = 0; 
       } 
      } 
      else if (n == '\n') 
       continu = 0; 
      else if (n == '\\' && !inword) 
       continu = 1; 
      else { 
       if (!inword) 
       { 
        inword = 1; 
        argv[m++] = p; 
        *p++ = n; 
       } 
       else 
        *p++ = n; 
      } 
     } /* end of command parsing */ 

     *p++ = 0; 
     argv[m] = 0; 

     /* user wishes to terminate program */ 
     if (strcmp(argv[0], "exit") == 0) 
      exit(0); 

     /* manage redirection */ 
     while (argv[count] != 0) { 
      if (strcmp(argv[count], "|") == 0) { 
       argv[count] = 0; 
       argumentContainer[pipes + 1] = count + 1; 
       ++pipes; 
      } 
      else if (strcmp(argv[count], "<") == 0) { 
       iPath = strdup(argv[count + 1]); /* copy string argument (file string) */ 
       argv[count] = 0; 
       argv[count + 1] = 0; 
       inputRedirectFlag = 1; 
      } 
      else if (strcmp(argv[count], ">") == 0) { 
       oPath = strdup(argv[count + 1]); /* copy string argument (file string) */ 
       argv[count] = 0; 
       argv[count + 1] = 0; 
       outputRedirectFlag = 1; 
      } 
      else { 
       argumentContainer[count] = count; 
      } 

      ++count; 
     } /* end of redirection management */ 

     /* execute commands [<= in for-loop; n pipes require n+1 processes] */ 
     for (int index = 0; index <= pipes; ++index) { 
      if (pipes > 0 && index != pipes) { /* if user has entered multiple commands with '|' */ 
       pipe(r_pipe); /* no pipe(l_pipe); r_pipe becomes next child's l_pipe */ 
      } 

      /* switch-statement for command execution */ 
      switch (pid = fork()) { 
       /* fork() error */ 
       case -1: perror("fork failed"); 
         break; 

       case 0: /* child process manages redirection and executes */ 
         if ((index == 0) && (inputRedirectFlag == 1)) { 
          int inputFileDescriptor = open(iPath, O_RDONLY , 0400); 
          if (inputFileDescriptor == -1) { 
           perror("input file failed to open\n"); 
           return(EXIT_FAILURE); 
          } 
          close(READ); 
          dup(inputFileDescriptor); 
          close(inputFileDescriptor); 
         } /* end of input redirection management */ 

         if ((index == pipes) && (outputRedirectFlag == 1)) { 
          int outputFileDescriptor = open(oPath, O_WRONLY | O_CREAT, 0755); 
          if (outputFileDescriptor < 0) { 
           perror("output file failed to open\n"); 
           return(EXIT_FAILURE); 
          } 
          close(WRITE); 
          dup(outputFileDescriptor); 
          close(outputFileDescriptor); 
         } /* end of output redirection management */ 

         /* manage pipes if (a) first child process, (b) middle child process, or (c) third/final child process */ 
         if (pipes > 0) { 
          if (index == 0){ /* first child process */ 
           close(WRITE); 
           dup(r_pipe[WRITE]); 
           close(r_pipe[WRITE]); 
           close(r_pipe[READ]); 
          } 
          else if (index < pipes) { /* middle child process */ 
           close(READ); 
           dup(l_pipe[READ]); 
           close(l_pipe[READ]); 
           close(l_pipe[WRITE]); 
           close(WRITE); 
           dup(r_pipe[WRITE]); 
           close(r_pipe[READ]); 
           close(r_pipe[WRITE]); 
          } 
          else { /* third/final child process */ 
           close(READ); 
           dup(l_pipe[READ]); 
           close(l_pipe[READ]); 
           close(l_pipe[WRITE]); 
          } 
         } 

         /* execute command */ 
         execvp(argv[argumentContainer[index]], &argv[argumentContainer[index]]); 

         /* if execvp() fails */ 
         perror("execution of command failed\n"); 

         break; 

       default: /* parent process manages the pipes for child process(es) */ 
         if (index > 0) { 
          close(l_pipe[READ]); 
          close(l_pipe[WRITE]); 
         } 
         l_pipe[READ] = r_pipe[READ]; 
         l_pipe[WRITE] = r_pipe[WRITE]; 

         /* parent waits for child process to complete */ 
         wait(&status); 

         break; 
      } /* end of switch-statement for command execution */ 
     } /* end of loop for all pipes */ 

     // clear all executed commands 
     for (int i = 0; i < 20; ++i) { 
      argv[i] = 0; 
     } 
    } 
} 

void clearArgumentContainer (int argumentContainer[]){ 
    // clear argument container 
    for (int i = 0; i < 20; ++i) { 
     argumentContainer[i] = 0; 
    } 
} 

Voici le fichier d'entrée que je utilise:

exécutable
Tim 3.5 
Todd 2.1 
Beth 3.9 
Jason 3.5 
Zander 3.3 
Alex 3.5 
Tyler 3.5 
Lauren 3.6 
Jack 2.3 
Amir 3.4 
Beth 3.2 

avant listera uniquement les noms avec GPAs supérieur à 3,0 exécutable de tri triera liste des noms par ordre alphabétique

+0

Les commentaires ne sont pas pour une discussion prolongée; cette conversation a été [déplacée pour discuter] (http://chat.stackoverflow.com/rooms/156760/discussion-on-question-by-douglas-adolph-c-shell-redirection-and-piping-working). – Andy

Répondre

1

Voici mon code de travail final. Il ne met pas en œuvre des built-ins comme cd, mais je prévois d'implémenter ces built-ins bientôt! Le programme répond aux exigences de l'affectation.

Mon principal changement est survenu lors de la gestion de la redirection. Je devais supprimer une ligne de code en deux endroits:

argv[count + 1] = 0; 

De la redirection pour « < » et « > ».

J'ai également ajouté du code pour gérer les connexions des tuyaux, que mon processus soit le premier enfant, le dernier ou un intermédiaire.

code:

/*********************************************************************************************** 
*********************************************************************************************** 
Student: Douglas Adolph 
Course: Operating Systems 
Project #: 2 

Program emulates shell, and can do the following: 

1. Can execute a command with the accompanying arguments. 
2. Recognize multiple pipe requests and handle them. 
3. Recognize redirection requests and handle them. 
4. Type "exit" to quit the shhh shell. 

Notes: 

Shell built-ins (cd, echo, etc.) not yet implemented 

REFERENCED: 

1. http://www.thinkplexx.com/learn/article/unix/command 
2. http://man7.org/linux/man-pages/man2/open.2.html 
3. https://stackoverflow.com/questions/19846272/redirecting-i-o-implementation-of-a-shell-in-c 
********************************************************************************************** 
*********************************************************************************************/ 

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

#ifndef READ 
#define READ 0 
#endif 

#ifndef WRITE 
#define WRITE 1 
#endif 

void clearArgIndexContainer (int argLocation[]); 

int main() { 
    /* variables for command parsing and storage*/ 
    char n, *parser, buf[80], *argv[20]; 
    int m, status, inword, continu; 

    /* variables and flags for redirection (note: C does not have type bool; using integer value 0 or 1) */ 
    char *in_path, *out_path; 
    int inputRedirectFlag, outputRedirectFlag; 

    /* variables for piping */ 
    int count, pipes; 
    pid_t pid; 

    /* left and right pipes */ 
    int l_pipe[2], r_pipe[2]; 

    /* container for recording argument locations in argv[] */ 
    int argLocation[20] = { 0 }; 

    while (1) { 

     /* reset parsing and piping variable values */ 
     m = inword = continu = count = pipes = pid = 0; 

     /* begin parsing at beginning of buffer */ 
     parser = buf; 

     /* reset redirection flags */ 
     inputRedirectFlag = outputRedirectFlag = 0; 

     /* print shell prompt */ 
     printf("\nshhh> "); 

     /* parse commands */ 
     while ((n = getchar()) != '\n' || continu) 
     { 
      if (n == ' ') { 
       if (inword) 
       { 
        inword = 0; 
        *parser++ = 0; 
       } 
      } 
      else if (n == '\n') 
       continu = 0; 
      else if (n == '\\' && !inword) 
       continu = 1; 
      else { 
       if (!inword) 
       { 
        inword = 1; 
        argv[m++] = parser; 
        *parser++ = n; 
       } 
       else 
        *parser++ = n; 
      } 
     } /* end of command parsing */ 

     /* append terminating character to end of parser buffer and argv buffer */ 
     *parser++ = 0; 
     argv[m] = 0; 

     /* user wishes to terminate program */ 
     if (strcmp(argv[0], "exit") == 0) 
      exit(0); 

     /* manage redirection */ 
     while (argv[count] != 0) { 
      if (strcmp(argv[count], "|") == 0) { 
       argv[count] = 0; 
       argLocation[pipes + 1] = count + 1; 
       ++pipes; 
      } 
      else if (strcmp(argv[count], "<") == 0) { 
       in_path = strdup(argv[count + 1]); 
       argv[count] = 0; 
       inputRedirectFlag = 1; 
      } 
      else if (strcmp(argv[count], ">") == 0) { 
       out_path = strdup(argv[count + 1]); 
       argv[count] = 0; 
       outputRedirectFlag = 1; 
      } 
      else { 
       argLocation[count] = count; 
      } 

      ++count; 
     } /* end of redirection management */ 

     /* execute commands [<= in for-loop; n pipes require n+1 processes] */ 
     for (int index = 0; index <= pipes; ++index) { 
      if (pipes > 0 && index != pipes) { /* if user has entered multiple commands with '|' */ 
       pipe(r_pipe); /* no pipe(l_pipe); r_pipe becomes next child's l_pipe */ 
      } 

      /* switch-statement for command execution */ 
      switch (pid = fork()) { 
       case -1: perror("fork failed"); /* fork() error */ 
         break; 

       case 0: /* child process manages redirection and executes */ 
         if ((index == 0) && (inputRedirectFlag == 1)) { 
          int inputFileDescriptor = open(in_path, O_RDONLY , 0400); 
          if (inputFileDescriptor == -1) { 
           perror("input file failed to open\n"); 
           return(EXIT_FAILURE); 
          } 
          close(READ); 
          dup(inputFileDescriptor); 
          close(inputFileDescriptor); 
         } /* end of input redirection management */ 

         if ((index == pipes) && (outputRedirectFlag == 1)) { 
          //printf("DEBUG: here we should be about to create our output file\n"); 
          int outputFileDescriptor = creat(out_path, 0700); 
          if (outputFileDescriptor < 0) { 
           perror("output file failed to open\n"); 
           return(EXIT_FAILURE); 
          } 
          close(WRITE); 
          dup(outputFileDescriptor); 
          close(outputFileDescriptor); 
         } /* end of output redirection management */ 

         /* manage pipes if (a) first child process, (b) in-between child process, or (c) final child process */ 
         if (pipes > 0) { 
          if (index == 0){ /* first child process */ 
           close(WRITE); 
           dup(r_pipe[WRITE]); 
           close(r_pipe[WRITE]); 
           close(r_pipe[READ]); 
          } 
          else if (index < pipes) { /* in-between child process */ 
           close(READ); 
           dup(l_pipe[READ]); 
           close(l_pipe[READ]); 
           close(l_pipe[WRITE]); 
           close(WRITE); 
           dup(r_pipe[WRITE]); 
           close(r_pipe[READ]); 
           close(r_pipe[WRITE]); 
          } 
          else { /* final child process */ 
           close(READ); 
           dup(l_pipe[READ]); 
           close(l_pipe[READ]); 
           close(l_pipe[WRITE]); 
          } 
         } 

         /* execute command */ 
         execvp(argv[argLocation[index]], &argv[argLocation[index]]); 

         /* if execvp() fails */ 
         perror("execution of command failed\n"); 

         break; 

       default: /* parent process manages the pipes for child process(es) */ 
         if (index > 0) { 
          close(l_pipe[READ]); 
          close(l_pipe[WRITE]); 
         } 
         l_pipe[READ] = r_pipe[READ]; 
         l_pipe[WRITE] = r_pipe[WRITE]; 

         /* parent waits for child process to complete */ 
         wait(&status); 

         break; 
      } /* end of switch-statement for command execution */ 
     } /* end of loop for all pipes */ 

     // clear all executed commands 
     for (int i = 0; i < 20; ++i) { 
      argv[i] = 0; 
     } 
    } 
} 

void clearArgIndexContainer (int argLocation[]){ 
    // clear argument container 
    for (int i = 0; i < 20; ++i) { 
     argLocation[i] = 0; 
    } 
} 

C'est là j'ai enlevé les lignes faisant argv [count + 1] = 0; :

/* manage redirection */ 
    while (argv[count] != 0) { 
     if (strcmp(argv[count], "|") == 0) { 
      argv[count] = 0; 
      argLocation[pipes + 1] = count + 1; 
      ++pipes; 
     } 
     else if (strcmp(argv[count], "<") == 0) { 
      in_path = strdup(argv[count + 1]); 
      argv[count] = 0; 
      inputRedirectFlag = 1; 
     } 
     else if (strcmp(argv[count], ">") == 0) { 
      out_path = strdup(argv[count + 1]); 
      argv[count] = 0; 
      outputRedirectFlag = 1; 
     } 
     else { 
      argLocation[count] = count; 
     } 

Ce fut mon principal plus de manipuler des tuyaux:

/* manage pipes if (a) first child process, (b) in-between child process, or (c) final child process */ 
         if (pipes > 0) { 
          if (index == 0){ /* first child process */ 
           close(WRITE); 
           dup(r_pipe[WRITE]); 
           close(r_pipe[WRITE]); 
           close(r_pipe[READ]); 
          } 
          else if (index < pipes) { /* in-between child process */ 
           close(READ); 
           dup(l_pipe[READ]); 
           close(l_pipe[READ]); 
           close(l_pipe[WRITE]); 
           close(WRITE); 
           dup(r_pipe[WRITE]); 
           close(r_pipe[READ]); 
           close(r_pipe[WRITE]); 
          } 
          else { /* final child process */ 
           close(READ); 
           dup(l_pipe[READ]); 
           close(l_pipe[READ]); 
           close(l_pipe[WRITE]); 
          } 
         } 

J'ai encore beaucoup à faire, à savoir la mise en œuvre des built-ins, mais aussi de mettre plus de cela en fonctions distinctes pour nettoyer le code et le rendre plus lisible. On m'a aussi donné de bons conseils sur certaines expressions qui pourraient être mieux écrites, et je m'y attaquerai bientôt.

+1

Bon travail. Suggérer d'initialiser 'char * in_path = NULL, * out_path = NULL;' et 'int l_pipe [2] = {0}, r_pipe [2] = {0};' pour éliminer les avertissements d'initialisation. –