2011-02-25 135 views
0

我已經完成了我的Unix操作系統的實踐,除了我的的問題與執行cat當它的輸出是一個文件; IE:cat foo.txt > bar.txt - 將foo的內容輸出到barUnix Shell在C - 文件描述符中實現Cat問題

讓我們從主要功能開始 &然後我將定義子方法:

int main(int argc, char **argv) 
{   
    printf("[MYSHELL] $ "); 

    while (TRUE) { 
     user_input = getchar(); 
     switch (user_input) { 

      case EOF: 
       exit(-1); 

      case '\n': 
       printf("[MYSHELL] $ "); 
       break; 

      default: 
       // parse input into cmd_argv - store # commands in cmd_argc 
       handle_user_input(); 

       //determine input and execute foreground/background process 
       execute_command(); 
     } 
     background = 0; 
    } 
    printf("\n[MYSHELL] $ "); 
    return 0;  
} 

handle_user_input只是填充cmd_argv陣列執行user_input,並刪除>和套如果用戶希望輸出到文件,則標誌爲output。這是該方法的肉:然後

while (buffer_pointer != NULL) { 
     cmd_argv[cmd_argc] = buffer_pointer; 
     buffer_pointer = strtok(NULL, " "); 

     if(strcmp(cmd_argv[cmd_argc], ">") == 0){ 
      printf("\nThere was a '>' in %s @ index: %d for buffer_pointer: %s \n", *cmd_argv,cmd_argc,buffer_pointer); 
      cmd_argv[cmd_argc] = strtok(NULL, " "); 
      output = 1; 
     } 

     cmd_argc++; 

     if(output){ 
      filename = buffer_pointer; 
      printf("The return of handling input for filename %s = %s + %s \n", buffer_pointer, cmd_argv[0], cmd_argv[1]); 
      return; 
     }   
} 

execute_command被調用時,解釋現在填充cmd_argv。只是想給你一個大局的想法。顯然,所有這些情況下比賽和create_process方法被稱爲:

int execute_command() 
{ 
    if (strcmp("pwd", cmd_argv[0]) == 0){ 
     printf("%s\n",getenv("PATH")); 
     return 1; 
    } 
    else if(strcmp("cd", cmd_argv[0]) == 0){ 
     change_directory(); 
     return 1;   
    } 
    else if (strcmp("jobs", cmd_argv[0]) == 0){ 
     display_job_list(); 
     return 1; 
    } 
    else if (strcmp("kill", cmd_argv[0]) == 0){ 
     kill_job(); 
    } 
    else if (strcmp("EOT", cmd_argv[0]) == 0){ 
     exit(1); 
    } 
    else if (strcmp("exit", cmd_argv[0]) == 0){ 
     exit(-1); 
    } 
    else{ 
     create_process(); 
     return; 
    } 
} 

相當直接的,對不對?


create_process在這裏我遇到的問題。

void create_process() 
{ 
    status = 0; 
    int pid = fork(); 
    background = 0; 

    if (pid == 0) { 
     // child process 
     if(output){ 
      printf("Output set in create process to %d\n",output); 
      output = 0; 
      int output_fd = open(filename, O_RDONLY); 
      printf("Output desc = %d\n",output_fd); 
      if (output_fd > -1) { 
       dup2(output_fd, STDOUT_FILENO); 
       close(output_fd); 
      } else { 
       perror("open"); 
      } 
     } 
     printf("Executing command, but STDOUT writing to COMMAND PROMPT instead of FILE - as I get the 'open' error above \n"); 
     execvp(*cmd_argv,cmd_argv); 
     // If an error occurs, print error and exit 
     fprintf (stderr, "unknown command: %s\n", cmd_argv[0]); 
     exit(0); 
    } else { 
     // parent process, waiting on child process 
      waitpid(pid, &status, 0); 
     if (status != 0) 
      fprintf (stderr, "error: %s exited with status code %d\n", cmd_argv[0], status); 
    } 
    return; 
} 

我打印output_fd = -1,我管理,以獲得其他說明裏面的perror("open")open: No such file or directory。然後打印出它是"writing to COMMAND PROMPT instead of FILE",因爲我顯示在控制檯上。然後執行execvp,它處理cat foo.txt,但將其打印到控制檯而不是文件。

我意識到它不應該在這一點上,因爲有output_fd = -1是不可取的,應該返回另一個值;但我無法弄清楚如何正確使用文件描述符,以打開一個新的/現有的文件並且寫入它,以及如何回到命令行的標準輸入。

我已經設法輸出到文件,但然後失去回來正確的標準輸入。有人可以指示我嗎?我覺得我正在圍繞一些愚蠢的事情,例如我正在做錯事或尋找過去。

任何幫助非常感謝。

+1

只要你知道「C Shell」就意味着與「用C寫的Shell」不同的東西。 – 2011-02-25 18:57:57

+0

沒錯。我改變了我的標題,使其更有意義。我正在用C語言實現一個UNIX shell,並複製基本shell中使用的相同命令。 – user546459 2011-02-25 19:08:33

回答

2

如果要寫入文件,爲什麼要使用O_RDONLY?我的猜測是你應該使用類似的東西:

int output_fd = open(filename, O_WRONLY|O_CREAT, 0666); 

(0666是建立創建時的訪問權限)。

很明顯,如果您無法打開重播文件,則不應啓動該命令。

+0

爲什麼我以前沒有想過這個!?我實際上正在寫入文件,而不是讀取它打開,而是執行一個命令並將其放入文件。這解決了寫作問題,我又得到了'user_input'!除了在下次執行命令時嘗試重新打開文件以清除我的情況以外,我還是免費的!再次感謝! – user546459 2011-02-25 19:24:58

1

首先,我注意到的很明顯的事情是,你已經打開文件O_RDONLY。不能很好地輸出!

其次,重定向輸出基本過程是:

  • 打開文件編寫
  • DUP標準輸出,因此您可以根據需要保留一份副本。如果重定向,則與stderr相同。
  • 的fcntl你雙份CLOEXEC(或者,使用DUP3)
  • DUP2文件到stdout
  • 執行的是命令

最後,你真的繞過命令名稱爲全局變量?我想這會回來困擾你,一旦你嘗試和實施cat foo | (cat bar; echo hi; cat) > baz或某些。