Экспортировать переменную env, которая будет доступна на всех вложенных оболочках, и возможно ли ее изменить?

22

Предположим, у меня есть

export MY_VAR=0

в ~/.bashrc.

У меня есть открытый терминал gnome, и в этом терминале я меняю $MY_VARзначение на 200. Итак, если я сделаю

echo $MY_VAR

в этом терминале 200показано.

Теперь я открыл еще одну вкладку в моем терминале гнома, и сделать

echo $MY_VAR

... и вместо этого у 200меня есть 0.

Что я должен сделать, чтобы сохранить значение 200, когда терминал изменяет переменную среды, делая это изменение (значение 200) доступным для всех последующих вложенных оболочек и тому подобное? Это возможно?

Кто-то все еще использует тебя MS-DOS
источник

Ответы:

23

Копия из среды распространяется на суб-оболочки, так это работает:

$ export MY_VAR=200
$ bash
$ echo $MY_VAR
200

но так как это копия, вы не можете получить это значение до родительской оболочки - по крайней мере, не изменяя среду.

Звучит так, будто вы действительно хотите пойти еще дальше: создать нечто, действующее как глобальная переменная, совместно используемую «родными» оболочками, инициированными отдельно от родителя, - как ваша новая вкладка в Gnome Terminal.

В большинстве случаев ответ таков: «Вы не можете, потому что переменные среды не работают таким образом». Тем не менее, есть другой ответ, который, ну, вы всегда можете взломать что-нибудь. Один из подходов - записать значение переменной в файл, например ~/.myvar, и затем включить его в ~/.bashrc. Затем каждая новая оболочка будет начинаться со значения, считанного из этого файла.

Вы могли бы пойти дальше - сделать так, чтобы ~/.myvarбыть в формате MYVAR=200, а затем установить PROMPT_COMMAND=source ~/.myvar, что приведет к тому, что значение будет перечитываться каждый раз, когда вы получаете новое приглашение. Это все еще не совсем общая глобальная переменная, но она начинает действовать так же. Он не будет активирован до тех пор, пока не вернется приглашение, что в зависимости от того, что вы пытаетесь сделать, может быть серьезным ограничением.

И затем, конечно, следующая вещь - автоматически записывать изменения в ~/.myvar. Это становится немного сложнее, и я собираюсь на этом остановиться, потому что на самом деле переменные среды не должны были быть механизмом взаимодействия между оболочками, и лучше просто найти другой способ сделать это.

mattdm
источник
10
Я слышу, как под пыткой
Да извини. Вот почему я остановился. :)
mattdm
«который должен создать что-то, что действует как глобальная переменная» - ну, действительно, это то, что я пытался сделать. ~ / .Myvar не симпатичен, но работает. У вас есть другое предложение?
Кто-то по-прежнему использует тебя MS-DOS
2
Что ж, давайте вернемся немного назад. Почему вы хотите глобальную переменную?
Mattdm
1
@mattdm: У меня есть «бюрократия», которой я должен подчиняться. Один из них - это набор кодов, которые мне нужно зафиксировать вместе с комментарием. Эти коды теперь находятся в иерархии папок (home / user / projects / projectcode / code1 / code2). Я сделал функцию, которая извлекает code1 и code2 в env vars (поэтому, когда мне нужно выполнить действие, я просто вызываю функцию внутри dir с кодами), и они, при фиксации, я использую vim, и есть некоторые функции, которые прочитайте эти переменные и добавьте комментарий автоматически. Я думаю, что использование файлов для этого может быть решением.
Кто-то все еще использует тебя MS-DOS
13

Предположим , у меня есть export MY_VAR=0в ~/.bashrc.

Это твоя ошибка прямо здесь. Вы должны определить переменные окружения ~/.profile, которые читаются при входе в систему. ~/.bashrcЧитаются при каждом запуске оболочки; когда вы запускаете внутреннюю оболочку, она переопределяет MY_VAR. Если вы этого не сделали, ваша переменная окружения будет распространяться вниз.

Для получения дополнительной информации о ~/.bashrcпротив ~/.profile, см. Мои предыдущие сообщения на эту тему .

Обратите внимание, что восходящее распространение (получение измененного значения из подоболочки автоматически отражается в родительской оболочке) невозможно, полная остановка.

Жиль "ТАК - перестань быть злым"
источник
4

Рыбная раковина может сделать это с:

set -U MY_VAR 0

(см. http://fishshell.com/docs/current/commands.html#set )

Чтобы выполнить команду fish из другой оболочки, вы можете запустить fish -c, например:

fish -c "set -u MY_VAR 0"
Рикард фон Эссен
источник
3

Не используйте переменные среды вообще. Используйте файлы.

Чтобы процессы не наступали друг на друга при обновлении / чтении файла, используйте lockfiles и небольшие внешние сценарии обновления, цель которых - просто обновить файл с $ 1, если он не заблокирован. Блокировочные файлы реализуются, в основном, проверкой, существует ли определенный файл (/var/run/yourscript.lck), и если это так, подождите, пока файл не исчезнет, ​​и потерпит неудачу, если его нет. Также вы должны удалить файл блокировки, когда закончите обновление файла.

Будьте готовы справиться с ситуацией, когда скрипт не может обновить файл, потому что файл занят.

LawrenceC
источник
8
Хитрость: используйте каталоги вместо файлов для блокировки, потому что mkdirработает как атомарное тестирование и создание.
Mattdm
1
Если вы , ребята , хотите , чтобы говорить о блокировке, то вы можете также использоватьflock(2)
Ehtesh Чоудхури
@mattdm Я обнаружил, что символическая ссылка ln -s dummy lockfile(даже если она не работает) может также работать, поскольку она не будет работать, если символическая ссылка уже существует. Интересно, какой-нибудь способ проверить, действительно ли это на 100% безопасно?
Водолей Сила
1

Когда я только что погуглил этот вопрос, я пытался решить проблему обновления состояния (т. Е. Переменных оболочки) из подоболочек. Чтобы можно было назначать переменные, скажем, внутри конвейера - и назначение было бы прозрачно видимым для родителя.

Конечно, это не возможно простым способом, потому что отдельные части конвейера выполняются в подоболочках, которые forkредактируются из родительской оболочки и, следовательно, имеют память, которая является представлением копирования при записи в памяти родителя. Тем не менее, я предполагал, что тонкое и прозрачное решение может быть возможным на основе IPC типа « разделяемая память » .

И я даже нашел реализацию именно этого дизайна ... но это на Perl.

Добавление этого ответа в любом случае в качестве возможного решения.

ulidtko
источник