2012-09-22 8 views
5

私は単純なシェルを作っています。また、行単位でテキストファイルを読むことができる必要があります。これは私のコードです:EOFのために終了する前に何度もfgetsがループする

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

私はシェルとして単独で実行すると素晴らしい動作します。 ./myshell < commands.txtを実行すると動作しません。

ls -l -a 
pwd 
ls 

しかし、出力は次のとおりです:

commands.txtがある

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

も私のコマンドを実行しません。何か案は?私はwhileループがとても簡単だと思った。

+0

のすべてに感謝。 –

+0

プロンプトを印刷した後に少なくとも出力をフラッシュする必要があるため、コマンド出力に対して適切な場所に出力されます。 –

+0

PIDを印刷すると、最後の1つを除いて、すべて0(各Bye!)が得られます。これは19147です。 – user1687558

答えて

3

の場合はの問題ですが、*argsの配列に「NULLポインタ用に1つ」を割り当てる必要があることを(正しく)コメントに記載しています。

ただし、実際には*argsの最後のポインタをNULLに設定しないでください。

execvp()はそれを好まないでしょう。

これは、リダイレクトされていない入力とリダイレクトされていない入力との間に違いがある理由を説明していません。

+0

ありがとうございます - 私は最後のポインタをNULLに設定しましたが、奇妙な動作がまだ起きています – user1687558

1

申し訳ありません - 私のテキストファイルは、MacのTextEdit GUIから何らかの種類の痴漢形式になっていました。すべてがうまくいっています。

私は本当に何を印刷したユーザーを確認)(my_exit中のプロセスのPIDを試してみて、印刷役立つ回答

+0

フォーマットについて欺かれたことと認知症がどのように現れたかについて詳しく説明できますか? –

+0

私はTextEditファイルを保存しましたが、それは.rtfだったので、名前を.txtに変更しました...これは、ファイルの先頭に(RTF形式について)奇妙な文字が続き、その後にコマンドが続きました。したがって、プログラムが.txt入力で実行されたとき、完全に奇妙なコマンドを実行しようとしていました。私はcatのコマンドを試してこれを見つけました.txt ...私は私のMac @ homeを介して私のUnix ServerにSSHingしてきたので、私が最初にTextEditを使用していた理由です。テスト用のテキストファイルを作成したかったので、TextEditで作成し、Cyber​​Duckを使用してSCPを作成しました。 – user1687558

関連する問題