简体   繁体   中英

zsh export with one argument does not seem to actually create environment variable

The command

export FOO

should, according to my understanding, create an environment variable FOO (with a blank value) even if this variable did not exist previously and no value was supplied. This position seems to be supported by the zsh manual. See the following from man zshbuiltins :

export [ name[=value] ... ]
    The specified names are marked for automatic export to the environment of subsequently executed commands.    Equivalent
    to typeset -gx.  If a parameter specified does not already exist, it is created in the global scope.

However, when I use C's getenv function, this environment variable is not registered. here is a simple example. Consider the following program:

 % cat foo.c
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    const char* foo = getenv("FOO");
    if ( foo == NULL ) {
        printf("The environment variable 'FOO' does not exist!\n");
    } else {
        printf("%s\n", foo);
        return 0;
    }
}

Compile it:

 % gcc --version
gcc (GCC) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 % gcc foo.c -o foo

Consider the following three executions:

 % ./foo
The environment variable 'FOO' does not exist!
 % export FOO
 % ./foo
The environment variable 'FOO' does not exist!
 % export FOO=BAR
 % ./foo
BAR

What is wrong in the middle case? Shouldn't it display a blank line?

Note that you didn't need to write your own program to display the env vars. The env command already exists:-)

This is a quirk that dates back at least four decades to the earliest UNIX shells. Modern shells (including bash, zsh, and ksh) all exhibit that quirk. The quirk is that if you export VAR and VAR has not already been assigned a value it is marked to be exported but will not actually be in the exported environment until you assign it a value. You can see this for yourself using any of those shells; not just zsh:

$ export FOO
$ env | grep FOO
$ FOO=''
$ env | grep FOO
FOO=
$ FOO=bar
$ env | grep FOO
FOO=bar
$ BAR=''
$ export BAR
$ env | grep BAR
BAR=

That last example hints at why export behaves this way.

There is some bug here. First, let's change the program to use the environment variables directly, avoiding the possibility of a bug in getenv :

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


int main(int argc, char *argv[], char *arge[])
{
    for (char **p = arge; *p; ++p)
        if (0 == strncmp(*p, "FOO", 3))
        {
            puts(*p);
            return 0;
        }
}

Now, if we build this and execute it in a fresh zsh , we get no output, as expected.

If we export FOO and execute it, we again get no output, but export | grep FOO export | grep FOO shows FOO='' . So zsh did define it, to be an empty string, but zsh failed to pass it to the program (or something in the environment-variable handling in the exec routines messed up).

However, start a fresh zsh , execute export FOO twice, and then the program. Now the output is FOO= . But export | grep FOO export | grep FOO still shows FOO='' . So there seems to be some hidden state in zsh : Sometimes it does not export defined variables.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM