2016-12-02 8 views
1

私は学校への割り当てに多くの問題があります。私はパイプとI/Oリダイレクションをcのシェル実装に追加することになっています。私はすでにI/Oリダイレクションで動作するようにしました。パイプは単独で動作しますが、この種の "sort < file.txt | grep main | cat>出力"をサポートする必要があります。私はそれを両方で同時に動作させる方法は知らない。どんな助けでも大歓迎です。パイプでのシェル実装とCでのI Oリダイレクト

int get_args(char* cmdline, char* args[]){ 
    int i = 0; 

    /* if no args */ 
    if((args[0] = strtok(cmdline, "\n\t ")) == NULL) 
    return 0; 
    while((args[++i] = strtok(NULL, "\n\t ")) != NULL) { 
    if(i >= MAX_ARGS) { 
    printf("Too many arguments!\n"); 
    exit(1); 
    } 
} 
/* the last one is always NULL */ 
return i; 
} 

void pipehandler(char* args[], int nargs){ 

    int num_cmds = 0; 
    char *command[256]; 
    int filedes[2]; // pos. 0 output, pos. 1 input of the pipe 
    int filedes2[2]; 
    int i = 0; 
    //calculate the number of commands 
    for(int i = 0; i < nargs; i++){ 
     if (strcmp(args[i], "|") == 0){ 
      num_cmds++; 
     } 
    } 
    num_cmds++; 
    if(num_cmds <= 1){ 
     return; 
    } 
    int j = 0; 
    int end = 0; 
    pid_t pid; 
    while(args[j] != NULL && end != 1){ 
     int k = 0; 

     while (strcmp(args[j],"|") != 0){ 
      command[k] = args[j]; 
      j++; 
      if (args[j] == NULL){ 
       // 'end' variable used to keep the program from entering 
       // again in the loop when no more arguments are found 
       end = 1; 
       k++; 
       break; 
      } 
      k++; 
     } 
     // Last position of the command will be NULL to indicate that 
     // it is its end when we pass it to the exec function 
     command[k] = NULL; 
     j++; 

    // Depending on whether we are in an iteration or another, we 
    // will set different descriptors for the pipes inputs and 
    // output. This way, a pipe will be shared between each two 
    // iterations, enabling us to connect the inputs and outputs of 
    // the two different commands. 
    if (i % 2 != 0){ 
     pipe(filedes); // for odd i 
    }else{ 
     pipe(filedes2); // for even i 
    } 
    pid=fork(); 

    if(pid==-1){ 
     if (i != num_cmds - 1){ 
      if (i % 2 != 0){ 
       close(filedes[1]); // for odd i 
      }else{ 
       close(filedes2[1]); // for even i 
      } 
     } 
     printf("Child process could not be created\n"); 
     return; 
    } 
    if(pid==0){ 
     // If we are in the first command 
     if (i == 0){ 
      dup2(filedes2[1], STDOUT_FILENO); 
     } 
     // If we are in the last command, depending on whether it 
     // is placed in an odd or even position, we will replace 
     // the standard input for one pipe or another. The standard 
     // output will be untouched because we want to see the 
     // output in the terminal 
     else if (i == num_cmds - 1){ 
      if (num_cmds % 2 != 0){ // for odd number of commands 
       dup2(filedes[0],STDIN_FILENO); 
      }else{ // for even number of commands 
       dup2(filedes2[0],STDIN_FILENO); 
      } 
     // If we are in a command that is in the middle, we will 
     // have to use two pipes, one for input and another for 
     // output. The position is also important in order to choose 
     // which file descriptor corresponds to each input/output 
     }else{ // for odd i 
      if (i % 2 != 0){ 
       dup2(filedes2[0],STDIN_FILENO); 
       dup2(filedes[1],STDOUT_FILENO); 
      }else{ // for even i 
       dup2(filedes[0],STDIN_FILENO); 
       dup2(filedes2[1],STDOUT_FILENO); 
      } 
     } 
     execvp(command[0],command); 
    } 

    // CLOSING DESCRIPTORS ON PARENT 
    if (i == 0){ 
     close(filedes2[1]); 
    } 
    else if (i == num_cmds - 1){ 
     if (num_cmds % 2 != 0){ 
      close(filedes[0]); 
     }else{ 
      close(filedes2[0]); 
     } 
    }else{ 
     if (i % 2 != 0){ 
      close(filedes2[0]); 
      close(filedes[1]); 
     }else{ 
      close(filedes[0]); 
      close(filedes2[1]); 
     } 
    } 

    waitpid(pid,NULL,0); 

    i++; 
    } 



} 

int searchIO(char* args[], int *nargs, char** input_file, char** output_file, int* in, int* out, int* ap){ 
int ioRedirection = -1; 
//search through the array args 
printf("searching for io redirections\n"); 
for(int i = 0; i < *nargs; i++){ 
    if(strcmp(args[i], "<") == 0){ 
     //if you find < then you need to redirect the stdin to be from a file 
     //if you are here then the input file is in args[i+1] 
     *input_file = args[i+1]; 
     printf("this is the input file %s \n", *input_file); 
     //we need to remove the < and input_file from args[] 
     int j; 
     for(j = i; j < *nargs; j++){ 
      //move what is in args[j+2] to args[j]; 
      args[j] = args[j+2]; 
     } 
     //then we need to execute the comand 
     *nargs = *nargs-2; 
     *in = 1; 
     i = 0; 
     ioRedirection = 1; 
    }else if (strcmp(args[i], ">") == 0){ 
     //if you are here then the output file is in args[i+1] 
     //so aparently execute what is in args[0] to args[i] 
     *output_file = args[i+1]; 
     //we need to remove the > and output_file from args[] 
     int j; 
     for(j = i; j < *nargs; j++){ 
      //move what is in args[j+2] to args[j]; 
      if(j < *nargs){ 
       args[j] = args[j+2]; 
      } 
     } 
     *nargs = *nargs-2; 
     *out = 1; 
     i = 0; 
     ioRedirection = 1; 
    }else if (strcmp(args[i], ">>") == 0){ 
     //if you are here then the output file is in args[i+1] 
     //so aparently execute what is in args[0] to args[i] 
     *output_file = args[i+1]; 
     //we need to remove the > and output_file from args[] 
     int j; 
     for(j = i; j < *nargs; j++){ 
      //move what is in args[j+2] to args[j]; 
      args[j] = args[j+2]; 
     } 
     *nargs = *nargs-2; 
     *out = 1; 
     *ap = 1; 
     i = 0; 
     ioRedirection = 1; 
    } 

    } 
    return -1; 

} 

void execute(char* cmdline){ 
int pid, async; 
char* args[MAX_ARGS]; 
char *input_file; 
char *output_file; 
int _in, _out, _ap; 
_in = 0; 
_out = 0; 
_ap = 0; 
int nargs = get_args(cmdline, args); 
pipehandler(args, nargs); 
searchIO(args, &nargs, &input_file, &output_file, &_in, &_out, &_ap); 
if(nargs <= 0) return; 
if(!strcmp(args[0], "quit") || !strcmp(args[0], "exit")) { 
     exit(0); 
} 
if(!strcmp(args[nargs-1], "&")) { async = 1; args[--nargs] = 0; } 
else async = 0; 

pid = fork(); 
if(pid == 0) { /* child process */ 
    if(_in == 1){ 
     int input = open(input_file, O_RDONLY); 
     dup2(input, STDIN_FILENO); 
     close(input); 
    } 
    if(_out == 1){ 
     int output; 
     if(_ap){ 
      output = open(output_file, O_APPEND | O_CREAT); 
     }else{ 
      output = open(output_file, O_CREAT | O_WRONLY, 0666); 
     } 

     dup2(output, STDOUT_FILENO); 
     close(output); 
    } 
execvp(args[0], args); 
/* return only when exec fails */ 
    perror("exec failed"); 
    exit(-1); 
    } else if(pid > 0) { /* parent process */ 
if(!async) waitpid(pid, NULL, 0); 
    else printf("this is an async call\n"); 
} else { /* error occurred */ 
perror("fork failed"); 
exit(1); 
} 
} 
int main (int argc, char* argv []) 
{ 
char cmdline[BUFSIZ]; 

    for(;;) { 
    printf("$ "); 
    if(fgets(cmdline, BUFSIZ, stdin) == NULL) { 
    perror("fgets failed"); 
    exit(1); 
    } 
    execute(cmdline) ; 
} 
return 0; 
} 
+0

これは宿題なので、リダイレクトを '|'でサポートするには、各プログラムの出力パイプを次のパイプに接続する必要があります。最後に '>'がある場合、ファイルを開き、最後のステージの出力をそのファイルにリダイレクトする必要があります。 – Davislor

+0

パイプが使用されている場合は、I/Oリダイレクトを使用する唯一の場所は、次のとおりです。http://stackoverflow.com/questions/3930339/implementing-pipes-in-ac-shell-unix?rq=1 – MrKiwi

+0

最初のコマンドと最後のコマンドではなく、中央の右に? – tommy

答えて

0

パイプがI/Oリダイレクションを使用する唯一の場所が使用されている場合、最初のコマンド で、最後の1ではなく、中央右にありますか?

これは、限りだけSTDIN/標準出力がリダイレクトされている唯一の真実です。

I/Oリダイレクションとパイプはそれ自身で動作しますが... ... どのようにして同時に動作させるかについてはわかりません。

実装を再構築してください。あなたはまた、パイプラインの最初のコマンドは、(間違った引数を指定してsearchIOから、その後、最初のpipehandlerから)2回実行されていることをエラーにつながる、お互いの後

pipehandler(args, nargs); 
searchIO(args, &nargs, &input_file, &output_file, &_in, &_out, &_ap); 

を呼び出す場合は機能しません。代わりにmainpipehandlerと呼び、の各コマンドをexecuteから呼び出すことができます(配管が1つのみあり、配管がない場合でも)。衝突するI/Oリダイレクションとパイプは簡単に診断できます。

関連する問題