2017-10-12 117 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};'消除初始化警告。 –