2017-10-12 1 views
2

Meine C-Shell kann die Umleitung erfolgreich verarbeiten (z. B. ls -al> output.txt, ./pre < input1.txt, usw.) und mehrere Rohre (dh cmd1 | cmd 2 | cmd 3). Mein Code funktioniert jedoch nicht, wenn ich versuche, Ein- und Ausgabeumleitungen zusammen mit einer Pipe auszuführen, z. B. ./pre < input.txt | ./sort> ausgabe.txt. Es wird keine Ausgabedatei erstellt, obwohl die Datei ./pre erfolgreich ausgeführt wird.C Shell: Umleitung und Verrohrung funktionieren, aber keine Kombination von Ein- und Ausgangsumleitung mit 1 oder mehreren Leitungen

pre ist eine ausführbare Datei, die Namen mit GPAs über 3,0

Art druckt ist eine ausführbare Datei, die eine Liste von Namen input.txt ist eine Datei mit Namen und GPAs (Name 3.1 ...) alphabetisiert.

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

Hier ist die Eingabedatei ich benutze:

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 

pre ausführbare Datei wird nur die Namen, die mit GPAs höher als 3,0 Art ausführbaren auflistet Liste der Namen sortieren in alphabetischer Reihenfolge

+0

Kommentare sind nicht für längere Diskussion; Diese Konversation wurde [in den Chat verschoben] (http://chat.stackoverflow.com/rooms/156760/discussion-on-question-by-douglas-adolph-c-shell-redirection-and-piping-working). – Andy

Antwort

1

Hier ist mein endgültiger Arbeitscode. Es implementiert keine integrierten Programme wie CD, aber ich plane, diese eingebauten Module bald zu implementieren! Programm erfüllt die Anforderungen für die Zuordnung.

Meine Hauptänderung trat in der Umleitungsbehandlung auf. Ich hatte eine Zeile Code an zwei Stellen zu entfernen:

argv[count + 1] = 0; 

Von der Umleitung für „<“ und „>“.

Ich fügte auch Code hinzu, um die Verbindungen der Rohre zu behandeln, ob mein Prozess das erste Kind war, das letzte oder eins dazwischen.

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

Dies ist, wo ich die Linien machen argv entfernt [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; 
     } 

Das war mein Hauptfach neben Rohre zu handhaben:

/* 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]); 
          } 
         } 

ich nämlich noch mehr Arbeit zu tun haben, die Einbauten der Umsetzung, sondern auch mehr davon in getrennte Funktionen setzen zu Bereinigen Sie den Code und machen Sie ihn lesbarer. Ich bekam auch einige gute Ratschläge für einige Ausdrücke, die besser geschrieben werden könnten, und ich werde mich bald damit befassen.

+1

Gute Arbeit. Schlage vor, dass du 'char * in_path = NULL, * out_path = NULL;' und 'int l_pipe [2] = {0}, r_pipe [2] = {0}; initialisierst, um Initialisierungswarnungen zu eliminieren. –

Verwandte Themen