2012-09-22 37 views
5

我正在製作一個簡單的shell。它還需要能夠按行讀取文本文件。這是我的代碼:fgets在退出EOF之前多次循環

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

// Exit when called, with messages 
void my_exit() { 
    printf("Bye!\n"); 
    exit(0); 
} 

int main(void) { 

    setvbuf(stdout, NULL, _IONBF, 0); 

    // Char array to store the input 
    char buff[1024]; 

    // For the fork 
    int fid; 

    // Get all the environment variables 
    char dir[50]; 
    getcwd(dir,50); 
    char *user = getenv("USER"); 
    char *host = getenv("HOST"); 

    // Issue the prompt here. 
    printf("%[email protected]%s:%s> ", user, host, dir); 

    // If not EOF, then do stuff! 
    while (fgets(buff, 1024, stdin) != NULL) { 

    // Get rid of the new line character at the end 
    // We will need more of these for special slash cases 
    int i = strlen(buff) - 1; 
    if (buff[i] == '\n') { 
     buff[i] = 0; 
    } 

    // If the text says 'exit', then exit 
    if (!strcmp(buff,"exit")) { 
     my_exit(); 
    } 

    // Start forking! 
    fid = fork(); 

    // If fid == 0, then we have the child! 
    if (fid == 0) { 

     // To keep track of the number of arguments in the buff 
     int nargs = 0; 

     // This is a messy function we'll have to change. For now, 
     // it just counts the number of spaces in the buff and adds 
     // one. So (ls -a -l) = 3. AKA 2 spaces + 1. Really in the 
     // end, we should be counting the number of chunks in between 
     // the spaces. 
     for (int i = 0; buff[i] != '\0'; i++) { 
     if (buff[i] == ' ') nargs ++; 
     } 

     // Allocate the space for an array of pointers to args the 
     // size of the number of args, plus one for the NULL pointer. 
     char **args = malloc((sizeof(char*)*(nargs + 2))); 

     // Set the last element to NULL 
     args[nargs+1] = NULL; 

     // Split string into tokens by space 
     char *temp = strtok (buff," "); 

     // Copy each token into the array of args 
     for (int i = 0; temp != NULL; i++) { 
     args[i] = malloc (strlen(temp) + 1); 
     strcpy(args[i], temp); 
     temp = strtok (NULL, " "); 
     } 

     // Run the arguments with execvp 
     if (execvp(args[0], args)) { 
     my_exit(); 
     } 
    } 

    // If fid !=0 then we still have the parent... Need to 
    // add specific errors. 
    else { 
     wait(NULL); 
    } 

    // Issue the prompt again. 
    printf("%[email protected]%s:%s> ", user, host, dir); 
    } 

    // If fgets == NULL, then exit! 
    my_exit(); 
    return 0; 
} 

當我單獨運行它作爲一個shell,它工作的很好。當我運行./myshell < commands.txt時,它不起作用。

commands.txt中是:

ls -l -a 
pwd 
ls 

但輸出是:

>Bye! 
>Bye! 
>Bye! 
>Bye! 
>Bye! 
>Bye!>Bye! 
>Bye! 
>Bye! 
>Bye! 

甚至不運行我的命令。有任何想法嗎?我認爲我的while循環非常簡單。

+0

嘗試並在my_exit()中打印進程的PID以查看誰在打印什麼。 –

+0

在打印提示後至少需要刷新輸出,以便它在相對於命令輸出的正確位置出現。 –

+0

打印PID,除了最後一個,我得到全0(每個再見!),這是19147 – user1687558

回答

3

我不知道這是問題,但你(正確地)中,你必須分配「加一個空指針」的*args陣列中的評論提及。

但是,你實際上並沒有設置最後指針*args爲NULL。

execvp()會不喜歡這樣。

這並不能解釋爲什麼有可能是重定向與非重定向輸入之間的差異,比未定義行爲等是個混蛋。

+0

謝謝 - 我已將最後一個指針設置爲NULL,並且奇怪的行爲仍在發生 – user1687558

1

對不起大家 - 原來我的文本文件是某種來自Mac的文本編輯GUI瘋狂的格式。一切都很好。

我真的很感謝所有有幫助的回覆

+0

您能否詳細說明什麼是關於格式的癡呆症,以及癡呆症是如何表現出來的? –

+0

當然!我保存了TextEdit文件,但是它是.rtf - 所以我只是將它重命名爲.txt ...這導致文件頂部出現了奇怪的字符(關於RTF格式),後面是命令。所以當程序運行.txt輸入時,它試圖執行完全奇怪的命令。我通過嘗試cat commands.txt找到了這個......我之所以使用TextEdit的原因是因爲我一直在通過我的Mac @ home進入我的Unix服務器。我想創建一個用於測試的文本文件,所以我在TextEdit中創建了它,並使用Cyber​​Duck將它交給SCP。 – user1687558