简单linux shell中的环境变量



我要为我的项目编程一个简单的shell,可以实现环境变量。我查了一下如何使用getenv, setenv, putenv。到目前为止,一切顺利,我已经尝试使用getenv来显示shell变量…取得了一些成功。但我感觉我的推理是有缺陷的。我有一个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 shell发现$符号,它在调用echo命令之前展开变量。我的shell没有遵循这个原则,它在echo命令本身中展开变量。任何想法,我如何才能实现这一点?谢谢。

编辑:

我有一个问题是:echo $HOMEecho 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()从命令行获得的输入

您明确要求代码对字符串执行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;
}

Edit:就你的方法而言,为什么你特别检查echo?为什么不让它泛型,并检查所有的参数,包括第一个?实际上,您可能希望替换所有可能的环境变量,因此,如果您在某处使用了MYECHO=echo,那么下面的代码就可以工作了。为了使它更通用,您将使用这个函数,它将根据展开的变量执行这些内容。您可以把它做得很好,并且有单独的函数,但是为了在这里容纳它,我已经相应地更新了上面的代码,尽管我还没有对它进行测试。;)

Edit:也就是说,werwindle之前关于这样做的评论确实适用——替换参数,就像这里一样,然后使用更新的参数数组让一个单独的函数做它需要做的任何事情。:)

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

Edit:对于putenv()的情况,您需要如下所示的结构。这样,它将为shell以及在shell中运行的任何其他进程设置它。

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(),则该子进程的兄弟进程(即从其父进程派生的其他进程)将不会获得环境更改。

很高兴我能帮上忙!

是的,普通shell在解析命令行时展开变量。所以你需要在函数中替换变量,生成"包含用户输入的解析输入"的数组。在这种情况下,echo(和其他命令)的代码将短得多。

最新更新