Я заинтересован в установке переменных среды одного экземпляра оболочки из другого. Поэтому я решил провести небольшое исследование. После прочтения ряда на вопросы о этом я решил проверить его.
Я породил две оболочки A и B (PID 420), обе работают zsh
. Из оболочки ИИ запускается следующее.
sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach
При запуске из оболочки B я env
вижу, что переменная FOO действительно установлена со значением bar. Это заставляет меня думать, что FOO была успешно инициализирована в среде оболочки B. Однако, если я пытаюсь напечатать FOO, я получаю пустую строку, подразумевая, что она не установлена. Мне кажется, что здесь есть противоречие.
Это было протестировано как на моей собственной системе Arch GNU / Linux, так и на виртуальной машине Ubuntu. Я также проверил это, bash
когда переменная даже не отображалась в env. Это, хотя и разочаровывает меня, имеет смысл, если оболочка кэширует копию своего окружения во время появления и использует только ее (что было предложено в одном из связанных вопросов). Это все еще не отвечает, почему zsh
можно увидеть переменную.
Почему вывод echo $FOO
пустой?
РЕДАКТИРОВАТЬ
После ввода комментариев я решил провести еще несколько тестов. Результаты можно увидеть в таблицах ниже. В первом столбце находится оболочка, в которую FOO
была введена переменная. Первая строка содержит команду, вывод которой можно увидеть под ней. Переменной FOO
вводили с помощью: sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'
. Команды, специфичные для zsh:, zsh -c '...'
также были протестированы с использованием bash. Результаты были идентичны, их вывод был опущен для краткости.
Arch GNU / Linux, zsh 5.3.1, bash 4.4.12 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Ubuntu 16.04.2 LTS, zsh 5.1.1, bash 4.3.48 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Вышеуказанное, по-видимому, подразумевает, что результаты не зависят от распределения. Это не говорит мне намного больше чем zsh
и bash
обрабатывает установку переменных по-другому. Кроме того, export FOO
имеет очень различное поведение в этом контексте в зависимости от оболочки. Надеемся, что эти тесты могут кое-что прояснить кому-то еще.
zsh -c 'echo $FOO'
вместо этого вы сделаете (используйте одинарные кавычки!)? Ты видишь это тогда?env
) видят измененную среду.zsh
в GDB не делает ее видимой в качестве переменной оболочки, но заставляет ее передаваться дочерним процессам (как вы наблюдали), при установке один дляbash
действительно сделать его видимым в качестве переменной оболочки , но это не причина, чтобы это было передано дочернему процессу! Похоже, что zsh и bash используют разные стратегии для управления переменными, при этом zsh отслеживает переменные, не относящиеся к среде, и bash хранит все в своей среде, которую он очищает при запуске дочернего (не подоболочечного) дочернего элемента.export FOO
вbash
?Ответы:
Большинство оболочек не используют
getenv()
/setenv()
/putenv()
API.После запуска они создают переменные оболочки для каждой переменной среды. Они будут храниться во внутренних структурах, которые должны нести другую информацию, например, экспортируется ли переменная, только для чтения ... Они не могут использовать библиотеки libc
environ
для этого.Точно так же, и по этой причине они не будут использовать
execlp()
,execvp()
чтобы выполнять команды , но вызватьexecve()
системный вызов напрямую, вычислениеenvp[]
массива на основе списка своих экспортируемых переменных.Таким образом, в вашем случае
gdb
вам нужно добавить запись в эту внутреннюю таблицу переменных оболочки или, возможно, вызвать нужную функцию, которая заставила бы ее интерпретироватьexport VAR=value
код для ее самостоятельного обновления.Относительно того , почему вы видите разницу между
bash
и ,zsh
когда вы звонитеsetenv()
вgdb
, я подозреваю , что это потому , что вы вызываетеsetenv()
перед инициализирует оболочки, например , при входеmain()
.Вы заметите,
bash
чтоmain()
естьint main(int argc, char* argv[], char* envp[])
(иbash
отображает переменные из этих переменныхenvp[]
), в то время какzsh
этоint main(int argc, char* argv[])
иzsh
получает переменныеenviron
вместо этого.setenv()
изменяет,environ
но не может изменятьenvp[]
на месте (только для чтения в нескольких системах, а также строки, на которые указывают эти указатели).В любом случае, после того, как оболочка прочитала
environ
при запуске, использованиеsetenv()
будет неэффективным, поскольку оболочка больше не используетenviron
(илиgetenv()
) впоследствии.источник