2017-04-22 46 views
2

你好,感謝你的關注。我正在嘗試實現我自己的shell。我有幾個關於我的代碼和關於任務解析的問題。下面我介紹我以前的代碼和問題:實施自己的外殼

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <signal.h> 
#include <string.h> 
#include <sys/wait.h> 
#include <sys/types.h> 
#include <ctype.h> 
#include <errno.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

void parse(char *line, char **argv, char **argv2) 
{ 
    while (*line != '\0') 
    { 
     while (*line == ' ' || *line == '\t' || *line == '\n') 
     { 
      *line++ = '\0'; 
     } 

     if(*line == '>' && *(line+1) == '>') 
     { 
      while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n') 
      { 
       line++; 
      }   
      while (*line == ' ' || *line == '\t' || *line == '\n') 
      {   
       *line++ = '\0'; 
      } 
      *argv2 = line; 
      break; 
     } 

     if(*line == '&') 
     { 
      break; 
     } 

     *argv++ = line; 

     while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n') 
     { 
      line++; 
     } 
    } 
    *argv = '\0'; 
} 

void execute(char **argv, int option) 
{ 
    pid_t pid; 
    int status; 

    if ((pid = fork()) < 0) 
    { 
     printf("*** ERROR ***\n"); 
     exit(1); 
    } 
    else if (pid == 0) 
    { 
     if (execvp(*argv, argv) < 0) 
     { 
      printf("*** ERROR ***\n"); 
      exit(1); 
     } 
    } 
    else if(option == 1) 
    { 
     while (wait(&status) != pid); 
    } 
} 

void execute2(char *command, char **argv, char **argv2) 
{ 
    pid_t pid; 
    int status; 

    if ((pid = fork()) < 0) 
    { 
     printf("*** ERROR ***\n"); 
     exit(1); 
    } 
    else if (pid == 0) 
    { 
     //close(1); 
     parse(command, argv, argv2); 
     int output = open(*argv2, O_APPEND | O_WRONLY); 
     dup2(output,1); 
     if (strcmp(argv[0], "exit") == 0) 
      exit(0); 
     if (execvp(*argv, argv) < 0) 
     { 
      printf("*** ERROR ***\n"); 
      exit(1); 
     } 
     close(output); 
    } 
    else 
    { 
     while (wait(&status) != pid); 
    } 
} 

int specialChar(char *argv) 
{ 
    int i=0; 
    while(argv[i]!='\0') 
    { 
     if(argv[i]=='>' && argv[i+1]=='>') 
      return 1;   
     else if(argv[i]=='&') 
      return 2;   
     else if(argv[i]=='|') 
      return 3;   
     i++; 
    } 
} 

void main() 
{ 
    char command[20]; 
    char *argv[64]; 
    char *argv2[1]; 
    char **history = (char**)malloc(20*sizeof(char*)); 
    int counterHistory1=-1; 
    int counterHistory2=0; 
    int i; 

    for(counterHistory2 = 0; counterHistory2<20; counterHistory2++) 
    { 
     history[counterHistory2]=(char*)malloc(100*sizeof(char)); 
    } 

    FILE *file; 
    file=fopen("history", "w"); 
    if(!file) 
     printf("ERROR"); 

    while (1) 
    { 
     printf("Shell -> "); 
     gets(command); 

     counterHistory1++; 
     strcpy(history[counterHistory1],command); 
     fopen("history", "w"); 
     if(counterHistory1<20) 
      for(i=0; i<=counterHistory1; i++) 
      { 
       fprintf(file,"%s\n",history[i]); 
      } 
     else 
      for(i=counterHistory1-20; i<counterHistory1; i++) 
      { 
       fprintf(file,"%s\n",history[i]); 
      } 

     fflush(file); 
     printf("\n"); 

     switch(specialChar(command)) 
     { 
      case 1: 
       //close(1); 
       execute2(command,argv,argv2); 
      break; 

      case 2:        //running program in background 
       parse(command, argv, argv2); 
       if (strcmp(argv[0], "exit") == 0) 
        exit(0); 
       execute(argv,0); 
      break; 

      case 3: 

      break; 

      default: 
       parse(command, argv, argv2); 
       if (strcmp(argv[0], "exit") == 0) 
        exit(0); 
       execute(argv,1); 
      break; 
     } 
     fclose(file); 
     } 
} 

1)當最後一個標誌從用戶剛開是「&」我需要在後臺運行我的程序。我已經讀過,如果我不打電話等待,我可以做到這一點。我做得很好還是應該改變一些東西?

2)如果我發現「>>」我應該重定向輸出到文件。例如,我得到ls >>輸出,所有的目錄和文件都應該寫入文件「輸出」。不幸的是,它只能使用一次。在此之後,我的程序停止。我認爲這個過程從來沒有完成,然後我不能寫下一個命令。我試圖殺死那個程序,但它沒有成功,或者我做錯了什麼。

3)在我的殼,我應該創建一個任意長度的管道|標誌。我不知道如何RESOLV這個問題......

感謝您的解答和幫助。

+0

下點2)是改進 – ByQ

+0

你的意思是你想寫解釋器本身?你能解釋一下「counterHistory1,2」,「歷史」是什麼? –

+0

只是一些建議 - 如果你沒有打開歷史文件,你爲什麼不暗戀?爲什麼你使用最大長度爲20的命令?沒什麼! –

回答

0

回答1

在殼,所創建的過程是殼的兒童,需要終端的控制下,通過獲得訪問到stdout,標準輸入和stderr

signal(SIGTTOU, SIG_IGN); 

    setpgid(getpid(),getpid()); 

    if(background==false) //shell for foreground process 
    { 
     tcsetpgrp(0,getpgid(getpid())); //access to stdin 
     tcsetpgrp(1,getpgid(getpid())); //access to stdout 
     tcsetpgrp(2,getpgid(getpid())); //access to stderr 
    } 
    execvp(command,args);