3

この質問の前に、私は C を初めて使用するため C が苦手であると述べたいと思います。そのため、あからさまなエラーやスタイルの悪さについて事前にお詫び申し上げます。また、コードを表示する前に問題を導入する方法がわからないので、ここに示します。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main()
{

    int MAX_INPUT_SIZE = 200;
    volatile int running = 1;
    while (running)
    {

        char input[MAX_INPUT_SIZE];
        char *tokens[100];
        const char *cmds[] = { "wait", "pwd", "cd", "exit" };
        char *cmdargs[100];

        printf("shell> ");
        fgets(input, MAX_INPUT_SIZE, stdin);

        // remove newline character at end
        int nl = strlen(input) - 1;
        if (input[nl] == '\n')
        {
            input[nl] = '\0';
        }

        // tokenize input string, put each token into an array
        char *space;
        space = strtok(input, " ");
        tokens[0] = space;

        int i = 1;
        while (space != NULL)
        {
            space = strtok(NULL, " ");
            tokens[i] = space;
            ++i;
        }

        // copy tokens after first one into string
        int noargscheck;
        if (tokens[1] != NULL)
        {
            noargscheck = 0;
            strcpy((char *)cmdargs, tokens[1]);
            for (i = 2; tokens[i] != NULL; i++)
            {
                strcat((char *)cmdargs, " ");
                strcat((char *)cmdargs, tokens[i]);
            }
        }
        else
        {
            noargscheck = 1;
        }

        // compare tokens[0] to list of internal commands
        int isInternal = -1;
        for (i = 0; i < 4; i++)
        {
            if (strcmp(tokens[0], cmds[i]) == 0)
            {
                isInternal = i;
            }
        }


        // internal commands
        char wd[200];
        if (isInternal != -1)
        {
            switch (isInternal)
            {
            case 0:
                // wait
                break;
            case 1:
                // pwd
                if (getcwd(wd, sizeof(wd)) == NULL)
                {
                    perror("getcwd() error!");
                }
                else
                {
                    printf("%s\n", wd);
                }
                break;
            case 2:
                // cd
                if (noargscheck)
                {
                    chdir("/home");
                }
                else if (chdir((const char *)cmdargs) != 0)
                {
                    perror("cd failed");
                }
                break;
            case 3:
                // exit
                exit(1);
                break;
            }
        }

        else
        {
            // external commands

            pid_t child_pid;
            switch (child_pid = fork())
            {
            case -1:
                perror("Fork failed");
                return 1;
            case 0:
                // child
                printf("\nHERE\n"); // for debugging
                execvp(tokens[0], cmdargs);
                break;
            }
        }
    }
}

このコードを input で実行すると、プログラムは で始まる 2 番目の switch ステートメントで case をecho hello world正常に入力しますが、予期しない出力は次のようになります。case 0switch (child_pid=fork())

出力: (プロンプトでの入力を示す 1 行を含む)

shell> echo hello world(私の入力)

shell>(ここがよく分からない部分です)

HERE

shell>(プログラムは、次のユーザー入力のプロンプトでここで待機します)

shell>余分なプロンプトが印刷される理由がわかりません。誰でも問題を見ることができますか?

編集: execvp の最初のパラメーターを修正しました。"echo"(私がばかだからそこにあった) から に変更されましたtokens[0]

4

2 に答える 2

0

cmdargs は 100 個の文字列ポインターの配列として定義されていますが、単一の文字列に対して 1 つの 100 バイトのバッファーとして使用しているようです。token[1] を特別に扱う理由もわかりません。token[0] だけが特別で、それがコマンドで、その他はすべて引数です。引数の処理は次のループにする必要があります

while (cmdargs[i++] = strtok(NULL, " "))

そして、execvp() の cmdargs の終了 NULL ポインター:

cmdargs[i] = NULL;

これはシェルであるため、子プロセスを待つことも忘れていました。最後の子プロセスが終了する前に、ユーザーに入力を求めるプロンプトを表示します。最終的な switch-case は次のようになります。

pid_t child_pid;
switch (child_pid = fork())
{
case -1:
    perror("Fork failed");
    return 1;
case 0:
    // child
    printf("\nHERE\n"); // for debugging
    execvp(tokens[0], cmdargs);
    perror("Exec failed");
    exit(1);
default:
    // parent
    int status;
    wait(&status);
    break;
}
于 2013-09-16T17:06:33.277 に答える