简单linux shell中的环境变量

发布于 2024-12-19 02:36:04 字数 1660 浏览 6 评论 0原文

我要为我的项目用 C 语言编写一个简单的 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()从命令行获取的输入

I am to program a simple shell in C for my project that can implement environment variables. I looked up on how to use the getenv, setenv, putenv. So far so good i've tried to use the getenv to show the shell variables...well... with some succes . But I have a feeling that my reasoning is flawed. I have a char** argv which contains parsed input from the user input. I now check if argv starts with the command "echo" and then if any of the following inputs starts with a $ sign or not. Here's my code:

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) == '

I think that normal linux shell finds the $ sign, it expands the variable before invoking the echo command. My shell isn't following this principle, it's expanding variables inside the echo command itself. Any idea as to how I can implement this? Thanks.

EDIT:

A problem I have is: echo $HOME and echo HOME gives me the same result which is wrong.

EDIT:

After various tests everything works well. But to really test it i'll need to create a local variable then echo this value. I tried it using putenv function but it doesn't create the local variable.

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 is the input gotten from the command line using fgets()

){ 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; }

I think that normal linux shell finds the $ sign, it expands the variable before invoking the echo command. My shell isn't following this principle, it's expanding variables inside the echo command itself. Any idea as to how I can implement this? Thanks.

EDIT:

A problem I have is: echo $HOME and echo HOME gives me the same result which is wrong.

EDIT:

After various tests everything works well. But to really test it i'll need to create a local variable then echo this value. I tried it using putenv function but it doesn't create the local variable.

userInput: char *userInput is the input gotten from the command line using fgets()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

眼波传意 2024-12-26 02:36:05

是的,普通 shell 在解析命令行期间会扩展变量。因此,您需要替换函数中的变量,该变量会生成“包含来自用户输入的解析输入”的数组。在这种情况下,echo(和其他命令)的代码将会短得多。

Yes, normal shells expand variables during parsing command line. So you need substitute variables in function, that produces array that "contains parsed input from the user input". In this case code for echo (and other commands) will be much shorter.

眼趣 2024-12-26 02:36:04

您专门要求代码对字符串执行 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 == '

编辑:就您的方法而言,为什么要专门检查回声?为什么不使其通用,并检查所有参数,包括第一个参数?您实际上可能想要替换所有潜在的环境变量,因此如果您在某处有 MYECHO=echo,则以下内容将起作用。为了使其更通用,您将拥有此函数,然后它将根据扩展的变量执行内容。您可以将其做得很好并具有单独的功能,但为了将其全部放在这里,我已经相应地更新了上面的代码,尽管我还没有测试它。 ;)

编辑:话虽这么说,werewindle 关于之前执行此操作的评论确实适用 - 替换参数,就像这里一样,然后使用更新后的参数数组让一个单独的函数执行它需要执行的任何操作。 :)

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

编辑: 对于 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
}

(希望最终)编辑:作为解释,进程通常不会(也许不能?)影响其层次结构中位于其上方的进程的环境;恰恰相反。因此,如果您将 env() 放入子进程中,则该子进程的兄弟进程(即从其父进程派生的其他进程)将不会获得环境更改。

很高兴我能帮上忙!

){ // 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 关于之前执行此操作的评论确实适用 - 替换参数,就像这里一样,然后使用更新后的参数数组让一个单独的函数执行它需要执行的任何操作。 :)

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

(希望最终)编辑:作为解释,进程通常不会(也许不能?)影响其层次结构中位于其上方的进程的环境;恰恰相反。因此,如果您将 env() 放入子进程中,则该子进程的兄弟进程(即从其父进程派生的其他进程)将不会获得环境更改。

很高兴我能帮上忙!

You're specifically asking the code to do getenv() for the string, even if $ isn't found. That's why it will lookup $HOME or HOME. Just remove the else case for not finding the dollar-sign, and make sure to initialize variable to NULL at its declaration, and put it inside the loop.

Something like so:

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

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

        if(*str == '

Edit: As far as your methodology goes, why do you specifically check for echo? Why not make it generic, and check all the arguments, including the first one? You actually probably want to substitute all the potential environment variables, so if you had MYECHO=echo somewhere, the following would work. To make it more generic, you'd have this function, which would then execute the stuff based on the expanded variables. You could make it all nice and have separate functions, but to fit it all in here, I've updated the code above accordingly, though I haven't tested it. ;)

Edit: That being said, werewindle's comment about doing this earlier does apply -- replace the arguments, like here, and then use that updated arguments array to have a separate function do whatever it needs to do. :)

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

Edit: As for the putenv() situation, you'll want something structured like the following. This way, it will set it for the shell, and any other processes you run in the 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
}

(Hopefully final) Edit: As an explanation, processes generally don't (perhaps can't?) affect the environment of processes above them in their hierarchy; only the other way around. So if you putenv() in a child, that child's siblings (i.e. other processes forked from its parent) won't get the environment change.

Glad I could be of help!

){ // 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: As far as your methodology goes, why do you specifically check for echo? Why not make it generic, and check all the arguments, including the first one? You actually probably want to substitute all the potential environment variables, so if you had MYECHO=echo somewhere, the following would work. To make it more generic, you'd have this function, which would then execute the stuff based on the expanded variables. You could make it all nice and have separate functions, but to fit it all in here, I've updated the code above accordingly, though I haven't tested it. ;)

Edit: That being said, werewindle's comment about doing this earlier does apply -- replace the arguments, like here, and then use that updated arguments array to have a separate function do whatever it needs to do. :)

Edit: As for the putenv() situation, you'll want something structured like the following. This way, it will set it for the shell, and any other processes you run in the shell.

(Hopefully final) Edit: As an explanation, processes generally don't (perhaps can't?) affect the environment of processes above them in their hierarchy; only the other way around. So if you putenv() in a child, that child's siblings (i.e. other processes forked from its parent) won't get the environment change.

Glad I could be of help!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文