zsh экспорт с одним аргументом не создает переменную среды - PullRequest
3 голосов
/ 22 февраля 2020

Команда

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

Что не так в среднем случае? Разве это не должно отображать пустую строку?

Ответы [ 2 ]

2 голосов
/ 23 февраля 2020

Обратите внимание, что вам не нужно было писать собственную программу для отображения переменных env. Команда env уже существует: -)

Это особенность, которая восходит по крайней мере на четыре десятилетия к самым ранним UNIX оболочкам. Современные оболочки (включая bash, zsh и k sh) демонстрируют эту причуду. Суть в том, что если вам export VAR и VAR еще не присвоено значение, оно помечается для экспорта, но фактически не будет в экспортированной среде, пока вы не назначите ему значение. Вы можете убедиться в этом сами, используя любую из этих оболочек; не просто 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 ведет себя так.

1 голос
/ 23 февраля 2020

Здесь есть какая-то ошибка. Во-первых, давайте изменим программу, чтобы она использовала переменные окружения напрямую, избегая возможности ошибки в 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;
        }
}

Теперь, если мы построим это и выполним это в свободном sh zsh мы не получаем никакого вывода, как ожидалось.

Если мы export FOO и выполним его, мы снова не получим никакого вывода, но export | grep FOO показывает FOO=''. Так zsh определил , что это пустая строка, но zsh не удалось передать ее программе (или что-то в обработке переменной среды в подпрограммах exec испортилось).

Однако запустите fre sh zsh, дважды выполните export FOO, а затем программу. Теперь вывод FOO=. Но export | grep FOO все еще показывает FOO=''. Так что, похоже, в zsh есть скрытое состояние: иногда оно не экспортирует определенные переменные.

...