带一个参数的 zsh export 似乎并没有真正创建环境变量

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

命令

export FOO
根据我的理解,

应该创建一个环境变量 FOO(具有空白值),即使该变量以前不存在且未提供任何值。 zsh 手册似乎支持这个立场。请参阅 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.

但是,当我使用C的getenv函数时,这个环境变量并没有被注册。这是一个简单的例子。考虑以下程序:

 % 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;
    }
}

编译它:

 % 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

考虑以下三个执行:

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

中间的情况有什么问题?它不应该显示一个空行吗?

这里有一些错误。首先,让我们将程序更改为直接使用环境变量,避免 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;
        }
}

现在,如果我们构建它并重新执行它 zsh,我们不会像预期的那样得到任何输出。

如果我们 export FOO 并执行它,我们再次没有输出,但 export | grep FOO 显示 FOO=''。所以 zsh did 将它定义为一个空字符串,但是 zsh 未能将它传递给程序(或 [=17= 中的环境变量处理中的某些内容) ] 例程搞砸了)。

但是,重新开始zsh,执行两次export FOO,然后程序。现在输出是 FOO=。但是export | grep FOO还是显示FOO=''。所以在zsh中似乎有一些隐藏状态:有时它不导出定义的变量。

请注意,您不需要编写自己的程序来显示环境变量。 env 命令已经存在:-)

这是一个至少可以追溯到四十年前最早的 UNIX shell 的怪癖。现代 shell(包括 bash、zsh 和 ksh)都表现出这种怪癖。奇怪的是,如果你 export VARVAR 还没有被分配一个值,它被标记为被导出但实际上不会在被导出的环境中,直到你为它分配一个值。您可以使用这些 shell 中的任何一个亲眼看到这一点;不只是 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=

最后一个例子暗示了为什么 export 会这样。