2017-10-12 136 views
2

我的C shell可以成功處理重定向(例如,ls -al> output.txt,./pre < input1.txt,等等)和多個管道(即cmd1 | cmd 2 | cmd 3)。但是,當我嘗試使用管道輸入和輸出重定向時,我的代碼不起作用,例如./pre < input.txt | ./sort> output.txt。儘管./pre執行成功,但沒有輸出文件。C shell:重定向和管道工作,但不是輸入和輸出重定向組合使用一個或多個管道

前是打印與GPA成績名字超過3.0

排序是按字母順序排列的名單 input.txt的是名稱和平均成績的文件的可執行文件(名稱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; 
    } 
} 

這裏是我使用的輸入文件:

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 

預可執行文件將只列出比3.0 排序可執行更高的GPA將整理名稱列表這些名字按字母順序排列

+0

評論不適用於擴展討論;這個對話已經[轉移到聊天](http://chat.stackoverflow.com/rooms/156760/discussion-on-question-by-douglas-adolph-c-shell-redirection-and-piping-working)。 – Andy

回答

1

這是我的最終工作代碼。它不像cd那樣實現內置插件,但我打算很快實現這些內置插件!計劃確實符合作業的要求。

我的重大變化發生在重定向處理。我不得不刪除一行代碼在兩個地方:

argv[count + 1] = 0; 

從重定向「<」和「>」。

我還添加了處理管道連接的代碼,無論我的過程是第一個孩子,最後一個還是介於兩者之間。

代碼:

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

這是我除去製作的argv線[計數+ 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; 
     } 

這是我的專業除了處理到管道:

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

我還有更多的工作要做,即實現內置插件,也把更多的這種成單獨的功能清理代碼並使其更具可讀性。對於某些可能寫得更好的表達方式,我也給了一些很好的建議,我很快就會解決這個問題。

+1

良好的工作。建議您初始化'char * in_path = NULL,* out_path = NULL;'和'int l_pipe [2] = {0},r_pipe [2] = {0};'消除初始化警告。 –