2

環境変数を実装できるプロジェクト用に C で簡単なシェルをプログラミングします。getenv、setenv、putenv の使い方を調べてみました。これまでのところ、getenvを使用してシェル変数を表示しようとしました...まあ...いくつか成功しました。しかし、私の推論には欠陥があると感じています。char** argvユーザー入力からの解析済み入力を含む があります。argvコマンド「echo」で始まるかどうかを確認し、次の入力のいずれかが$記号で始まるかどうかを確認します。これが私のコードです:

int executeVariables(char** arguments){
    int i = 0;
    if(strcmp(arguments[i], "echo") == 0){
        char *variable;
        for(i = 1; arguments[i] != NULL; i++){
            char *str = arguments[i];
            if( *(str + 0) == '$'){
                variable = getenv(str + 1);
            }else{
                variable = getenv(str);
            }
            if(!variable){
                //puts("not a variable");
                printf("%s ", arguments[i]);
            }else{
                //puts("a variable");
                printf("%s ", variable);
            }
        }
        printf("\n");
        exit(0);
    }

    return 1;

}

$通常のLinuxシェルは記号を見つけて、echoコマンドを呼び出す前に変数を展開すると思います。私のシェルはこの原則に従っていません。echo コマンド自体の中で変数を展開しています。これをどのように実装できるかについてのアイデアはありますか? ありがとう。

編集:

私が抱えている問題は次echo $HOMEのとおりecho HOMEです。同じ結果が間違っています。

編集:

さまざまなテストの後、すべてがうまく機能します。しかし、実際にテストするには、ローカル変数を作成してからechoこの値を作成する必要があります。関数を使用して試しましたputenvが、ローカル変数が作成されません。

i = 0;
char** temp = malloc(sizeof (*temp));
if(strstr(userInput, "=") != NULL){
    //puts("we got equals");
    puts(userInput);
    if(putenv(userInput) == 0){
       printf("doing putenv(%s)\n", userInput);
        exit(0);
    }
    else{
        puts("couldnt putenv");
       exit(1);
    }
}

userInput:char *userInputを使用してコマンド ラインから取得した入力です。fgets()

4

2 に答える 2

4

$ が見つからない場合でも、文字列に対して getenv() を実行するようにコードに具体的に要求しています。そのため、$HOME または HOME を検索します。ドル記号が見つからない場合のelseケースを削除し、宣言時に変数をNULLに初期化して、ループ内に配置してください。

そのようなもの:

// First, perform replacements
int executeVariables(char** arguments){
    int i = 0;

    for(i = 0; arguments[i] != NULL; i++){
        char *str = arguments[i];

        if(*str == '$'){
            // make sure the result isn't NULL, though I'm not sure a real shell does
            char *tmp = getenv(str + 1);
            if (tmp != NULL) {
                arguments[i] = getenv(str + 1); // save off the argument
            }
        }
    }

    // Then actually execute the function. This would be like bash's echo builtin
    if (strcmp(arguments[0], "echo") == 0) {
        int i;
        for (i = 1; arguments[i] != NULL; i++) {
            printf("%s ", arguments[i]);
        }
        printf("\n");
    }

    // Other functions could go here

    return 1;
}

編集:あなたの方法論に関する限り、なぜ特にエコーをチェックするのですか? ジェネリックにして、最初の引数を含むすべての引数をチェックしてみませんか? 実際には、潜在的な環境変数をすべて置き換えたいと思うかもしれません。そのため、MYECHO=echo がどこかにあれば、次のように動作します。より一般的にするには、この関数を使用します。この関数は、展開された変数に基づいて実行します。すべてを適切に作成して個別の機能を持たせることもできますが、すべてをここに収めるために、上記のコードをそれに応じて更新しましたが、テストはしていません。;)

編集:そうは言っても、これを以前に行うことに関するwerewindleのコメントは適用されます-ここのように引数を置き換えてから、その更新された引数配列を使用して、別の関数に必要なことを実行させます。:)

> $MYVAR totally awesome $HOME
totally awesome /home/user

編集: putenv() の状況に関しては、次のような構造が必要です。このようにして、シェル、およびシェルで実行するその他のプロセスに対して設定します。

void do_args_env(char *args[])
{
    // do putenv, etc.
}

// inside main loop in shell process
while (1) { // just an example
    if (check_args_syntax(args) != 0) {
        // error
    }

    do_args_env(args);

    // fork and do other stuff
}

(できれば最終)編集:説明として、プロセスは通常、階層内でそれらの上にあるプロセスの環境に影響を与えません(おそらく影響しませんか?)。その逆だけです。したがって、子で putenv() を実行すると、その子の兄弟 (つまり、親からフォークされた他のプロセス) は環境の変更を取得しません。

お役に立ててよかったです!

于 2011-11-30T15:48:43.320 に答える
1

はい、通常のシェルはコマンドラインの解析中に変数を展開します。そのため、「ユーザー入力からの解析された入力を含む」配列を生成する関数に代替変数が必要です。この場合、echo(およびその他のコマンド) のコードははるかに短くなります。

于 2011-11-30T15:37:25.460 に答える