2010-10-14 6 views
5

Grundsätzlich habe ich eine Shell mit POSIX-Standardbefehlen erstellt, ich möchte auch Piping implementieren können. Im Moment behandelt es Befehle korrekt und kann Hintergrundverarbeitung mit & durchführen. Aber ich muss mit | pipen können und >> auch. Zum Beispiel so etwas wie: cat file1 file2 >> file3 cat file1 file2 | mehr mehr file1 | grep stuffImplementieren von Pipes in einer C-Shell (Unix)

Hier ist der Code, den ich derzeit habe. Ich möchte auch "SYSTEM" -Aufrufe vermeiden. Ich weiß, dass Du dup2 verwenden musst, aber die Art und Weise, wie ich meinen Code gemacht habe, ist etwas merkwürdig, also hoffe ich, dass mir jemand sagen kann, ob es möglich ist, Pipes in diesem Code zu implementieren? Vielen Dank! Ich weiß, dup2 wird verwendet, aber auch im def. verwirrt darüber, wie man >> ebenso wie |

#include <sys/wait.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <string.h> 
#include <string> 
#include <iostream> 
#include <stdlib.h> 
#include <stdio.h> 

using namespace std; 


void Execute(char* command[],bool BG) 
{ 
//Int Status is Used Purely for the waitpid, fork() is set up like normal. 
    int status; 
    pid_t pid = fork(); 


    switch(pid) 
    { 
     case 0: 
      execvp(command[0], command); 

      if(execvp(command[0], command) == -1) 
      { 
       cout << "Command Not Found" << endl; 
       exit(0); 
      } 

      default: 
      if(BG == 0) 
      { 
        waitpid(pid, &status, 0); 
//Debug    cout << "DEBUG:Child Finished" << endl; 
      } 


    } 

} 


bool ParseArg(char* prompt, char* command[], char Readin[],bool BG) 
{ 

    fprintf(stderr, "myshell>"); 
     cin.getline(Readin,50); 
    prompt = strtok(Readin, " "); 
    int i = 0; 

    while(prompt != NULL) 
    { 
     command[i] = prompt; 
     if(strcmp(command[i], "&") == 0){ 
//Debug  cout << "& found"; 
     command[i] = NULL; 
     return true; 
    } 
//Debug  cout << command[i] << " "; 
     i++; 
     prompt = strtok(NULL, " "); 

    } 
    return false; 
} 

void Clean(char* command[]) 
{ 
//Clean Array 
     for(int a=0; a < 50; a++) 
     { 
      command[a] = NULL; 
     } 
} 



int main() 
{ 
    char* prompt; 
    char* command[50]; 
    char Readin[50]; 
    bool BG = false; 



    while(command[0] != NULL) 
    { 

     Clean(command); 
     BG = ParseArg(prompt, command, Readin, BG); 
     if(strcmp(command[0], "exit") == 0 || strcmp(command[0], "quit") == 0) 
     { 
      break; 
     } 

    else 
    { 
      Execute(command,BG); 
    } 

    } 

    return 1; 

} 
+3

Warum haben Sie versucht, Systemaufrufe zu vermeiden? Portabilität? Sie können so lange wie möglich bei den von POSIX angegebenen Systemaufrufen bleiben. Außerdem ist Ihre Shell eine seltsame Mischung aus C und C++. – nategoose

Antwort

5

Sie sollten in der Lage sein, Rohre und Ausgabeumleitung mit der Shell zu implementieren, aber es gibt ein paar Dinge, die ich bemerkt:

  • Ihr Code-Eingabe für das Lesen, das Parsen und Ausgang miteinander vermischt sind, können Sie möchte diese Funktionalität trennen.
  • strtok wird nicht sehr gut als Parser für Shell-Befehle arbeiten. Es wird für sehr einfache Befehle funktionieren, aber Sie sollten vielleicht in die Erstellung oder das Finden eines besseren Parsers schauen. Ein Befehl wie echo "hello world" wird mit Ihrer aktuellen Analysemethode problematisch sein.
  • Sie möchten vielleicht eine einfache Struktur zum Speichern Ihrer geparsten Befehle erstellen.

Hier einige Pseudo-Code Ihnen den Einstieg:

#define MAX_LINE 10000 
#define MAX_COMMANDS 100 
#define MAX_ARGS 100 

// Struct to contain parsed input 
struct command 
{ 
    // Change these with IO redirection 
    FILE *input; // Should default to STDIN 
    FILE *output; // Should default to STDOUT 

    int num_commands; 
    int num_args[MAX_COMMANDS]; // Number of args for each command 
    char* command_list[MAX_COMMANDS]; // Contains the programs to be run 
    char* args_list[MAX_COMMANDS][MAX_ARGS]; // The args for each command 
    boolean background_task; 
    boolean append; 
} 

int main() 
{ 
    char input[MAX_LINE]; 

    while (1) 
    { 
     struct command cmd; 

     print_prompt(); 
     read_input(input); 
     parse_input(input, &cmd); 
     execute(&cmd); 
    } 
} 

Viel Glück mit diesem Projekt!

5

Rohre und Umleitungen sind tatsächlich anders. Um eine Umleitung zu implementieren (wie >>) müssen Sie dup2 verwenden. Öffnen Sie zuerst die gewünschte Datei mit den entsprechenden Flags (für >> werden sie O_WRONLY|O_CREAT|O_APPEND sein). Zweitens, unter Verwendung von dup2, make stdout (Dateideskriptor 1) eine Kopie dieses neu geöffneten fd. Schließlich, schließen Sie neu geöffnet fd.

Um eine Pipe zu erstellen, benötigen Sie einen pipe Syscall. Lesen Sie seine Manpage, es enthält Beispielcode. Dann benötigen Sie auch dup2, um Dateideskriptoren, die von pipe zurückgegeben werden, für einen Prozess stdin und für einen anderen stdout zu machen.

+0

Glaubst du, mit der Art, wie ich meine Shell gemacht habe, wird es "möglich" sein oder sollte ich meine Shell neu gestalten? –

Verwandte Themen