2010-10-14 10 views
5

Zasadniczo utworzyłem powłokę przy użyciu standardowych poleceń POSIX, chcę też móc implementować orurowanie. Obecnie obsługuje poprawnie polecenia i może wykonywać przetwarzanie w tle za pomocą &. Ale muszę mieć możliwość potokowania używając | i >> również. Na przykład coś takiego: cat plik1 plik2 >> plik3 cat plik1 plik2 | więcej więcej file1 | grep stuffImplementowanie potoków w powłoce C (Unix)

Oto kod, który mam obecnie. Chcę również UNIKAĆ połączeń "SYSTEM". Wiem, że muszę używać dup2, ale sposób, w jaki zrobiłem mój kod jest trochę dziwny, więc mam nadzieję, że ktoś może mi powiedzieć, czy możliwe jest wdrożenie rur w tym kodzie? dzięki! Wiem, że używa się dup2, ale także im def. mylić, jak wdrożyć >> tak dobrze, jak |

#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

Dlaczego próbujesz uniknąć wywołań systemowych? Ruchliwość? Możesz trzymać się określonych wywołań systemu POSIX w jak największym stopniu. Co więcej, twoja powłoka to dziwna mieszanka C i C++. – nategoose

Odpowiedz

5

Powinieneś być w stanie realizować rur i wyjście przekierowanie ze swojej skorupy, ale istnieje kilka rzeczy, zauważyłem:

  • Twój kod do odczytu wejścia, przetwarzania i wyjścia są mieszane ze sobą, możesz chcesz oddzielić tę funkcjonalność.
  • strtok nie będzie działał bardzo dobrze jako parser dla poleceń powłoki. Będzie działać dla bardzo prostych poleceń, ale możesz chcieć zajrzeć do tworzenia lub znalezienia lepszego parsera. Polecenie takie jak echo "hello world" będzie problematyczne z twoją obecną metodą analizowania.
  • Możesz utworzyć prostą strukturę do przechowywania analizowanych poleceń.

Oto pseudokod możesz zacząć:

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

Powodzenia z tym projektem!

5

Rury i przekierowania są w rzeczywistości różne. Aby zaimplementować przekierowanie (takie jak >>), musisz rzeczywiście użyć dup2. Najpierw otwórz żądany plik z odpowiednimi flagami (dla >> będą one O_WRONLY|O_CREAT|O_APPEND). Po drugie, używając dup2, stdout (deskryptor pliku 1) jest kopią tego nowo otwartego pliku fd. Na koniec zamknij nowo otwarte fd.

Do utworzenia potoku potrzebny jest układ szeregowy pipe. Przeczytaj jego stronę podręcznika, zawiera przykładowy kod. Będziesz także potrzebował dup2, aby deskryptory plików zwracane przez pipe były stdin dla jednego procesu, a stdout dla innego, odpowiednio.

+0

Czy myślisz, że tak jak zrobiłem moją muszlę, będzie to "możliwe", czy powinienem przeprojektować swoją powłokę? –

Powiązane problemy