2010-10-14 15 views
5

Fondamentalmente ho creato una shell usando i comandi POSIX standard, voglio essere in grado di implementare anche Piping. In questo momento gestisce i comandi correttamente e può eseguire l'elaborazione in background con &. Ma ho bisogno di essere in grado di usare pipe e >> pure. Ad esempio qualcosa del genere: cat file1 file2 >> file3 cat file1 file2 | altro altro file1 | grep stuffImplementazione di pipe in una shell C (Unix)

Ecco il codice che ho attualmente. Voglio anche EVITARE le chiamate "SYSTEM". So che ho bisogno di usare dup2, ma il modo in cui ho fatto il mio codice è un po 'strano, quindi spero che qualcuno possa dirmi se è possibile implementare pipe in questo codice? Grazie! So che è usato dup2, ma anche im def. confuso su come implementare >> come BENE come |

#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

Perché stavi cercando di evitare le chiamate di sistema? Portabilità? È possibile attaccare il più possibile le chiamate di sistema specificate da POSIX. Inoltre, la shell è uno strano mix di C e C++. – nategoose

risposta

5

Si dovrebbe essere in grado di implementare pipe e il ridirezionamento di uscita con la shell, ma ci sono un paio di cose che ho notato:

  • il codice per leggere l'input, l'analisi, e l'uscita sono mescolati insieme, si può voglio separare questa funzionalità.
  • strtok non funziona molto bene come parser per i comandi di shell. Funzionerà per comandi molto semplici, ma potresti voler creare o trovare un parser migliore. Un comando come echo "hello world" sarà problematico con il tuo attuale metodo di analisi.
  • Si consiglia di creare una struttura semplice per contenere i comandi analizzati.

Ecco alcuni pseudocodice per iniziare:

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

Buona fortuna con questo progetto!

5

Tubi e reindirizzamenti sono diversi, in realtà. Per implementare un reindirizzamento (ad esempio >>), è necessario utilizzare dup2. Innanzitutto, apri il file desiderato con i flag appropriati (per >> saranno O_WRONLY|O_CREAT|O_APPEND). Secondo, usando dup2, fai stdout (descrittore di file 1) una copia di questo fd appena aperto. Infine, chiudi di recente aperto fd.

Per creare una pipe, è necessario un syscall pipe. Leggi la sua manpage, contiene codice di esempio. Quindi è necessario anche dup2 per rendere i descrittori di file restituiti da pipe essere stdin per un processo e stdout per un altro, rispettivamente.

+0

Pensi che con il modo in cui ho fatto il mio guscio sarà "possibile" o dovrei ridisegnare il mio guscio? –