Почему переменные среды, установленные в python, не сохраняются? - PullRequest
40 голосов
/ 04 апреля 2009

Я надеялся написать скрипт на python для создания некоторых подходящих переменных среды, запустив скрипт в любом каталоге, в котором я буду выполнять код моделирования, и я прочитал, что не могу написать скрипт для создания этих env переменные сохраняются в терминале Mac OS. Итак, две вещи:

Это правда?

и

Кажется, это было бы полезно сделать; почему это вообще невозможно?

Ответы [ 6 ]

32 голосов
/ 04 апреля 2009

Вы не можете сделать это из Python, но некоторые хитрые трюки с Bash могут сделать нечто подобное. Основная причина такова: переменные среды существуют в пространстве памяти для каждого процесса. Когда новый процесс создается с помощью fork (), он наследует переменные окружения своего родителя. Когда вы устанавливаете переменную окружения в вашей оболочке (например, bash) следующим образом:

export VAR="foo"

То, что вы делаете, говорит bash, чтобы установить переменную VAR в своем пространстве процесса на «foo». Когда вы запускаете программу, bash использует fork (), а затем exec () для запуска программы, поэтому все, что вы запускаете из bash, наследует переменные окружения bash.

Теперь предположим, что вы хотите создать команду bash, которая устанавливает некоторую переменную среды DATA с содержимым из файла в вашем текущем каталоге с именем ".data". Во-первых, вам нужна команда для извлечения данных из файла:

cat .data

Это печатает данные. Теперь мы хотим создать команду bash для установки этих данных в переменную окружения:

export DATA=`cat .data`

Эта команда берет содержимое .data и помещает его в переменную окружения DATA. Теперь, если вы поместите это в команду псевдонима, у вас есть команда bash, которая устанавливает переменную среды:

alias set-data="export DATA=`cat .data`"

Вы можете поместить эту команду псевдонима в файлы .bashrc или .bash_profile в вашем домашнем каталоге, чтобы эта команда была доступна в любой новой оболочке bash, которую вы запускаете.

19 голосов
/ 04 апреля 2009

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

thescript.py:

import pipes
import random
r = random.randint(1,100)
print("export BLAHBLAH=%s" % (pipes.quote(str(r))))

.. и псевдоним bash (то же самое можно сделать в большинстве оболочек .. даже tcsh!):

alias setblahblahenv="eval $(python thescript.py)"

Использование:

$ echo $BLAHBLAH

$ setblahblahenv
$ echo $BLAHBLAH
72

Вы можете вывести любой произвольный код оболочки, включая несколько команд, таких как:

export BLAHBLAH=23 SECONDENVVAR='something else' && echo 'everything worked'

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

3 голосов
/ 04 апреля 2009

Если вы установите переменные среды внутри скрипта Python (или любого другого скрипта или программы), это не повлияет на родительскую оболочку.

Редактировать уточнение: Так что ответ на ваш вопрос - да, это правда. Однако вы можете экспортировать из сценария оболочки и получить его с помощью вызова точки

в fooexport.sh

export FOO="bar"

в командной строке

$ . ./fooexport.sh
$ echo $FOO
bar
2 голосов
/ 04 апреля 2009

Что мне нравится делать, так это использовать / usr / bin / env в сценарии оболочки, чтобы «обернуть» мою командную строку, когда я нахожусь в похожих ситуациях:

#!/bin/bash

/usr/bin/env NAME1="VALUE1" NAME2="VALUE2" ${*}

Итак, давайте назовем этот скрипт "myappenv". Я положил его в каталог $ HOME / bin, который находится в моем каталоге $ PATH.

Теперь я могу вызвать любую команду, использующую эту среду, просто добавив «myappenv» как таковой:

myappenv dosometask -xyz

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

Модифицированная версия на основе новых комментариев

#!/bin/bash

/usr/bin/env G4WORKDIR=$PWD ${*}

Вы можете также обернуть это все в псевдоним. Я предпочитаю подход с использованием сценариев-оберток, так как я, как правило, готовлю другую среду, что облегчает мне поддержку.

1 голос
/ 04 апреля 2009

Это вообще невозможно. Новый процесс, созданный для python, не может влиять на среду его родительского процесса. Родитель также не может влиять на дочернего элемента, но родительский элемент может настроить дочернюю среду как часть создания нового процесса.

Возможно, вы можете установить их в .bashrc, .profile или эквивалентном сценарии «запускается при входе в систему» ​​или «запускается при каждом новом терминальном сеансе» в MacOS.

Вы также можете сделать так, чтобы python запускал программу симуляции в нужной среде. (используйте параметр env для подпроцесса. Открыть (http://docs.python.org/library/subprocess.html))

import subprocess, os
os.chdir('/home/you/desired/directory')
subprocess.Popen(['desired_program_cmd', 'args', ...], env=dict(SOMEVAR='a_value') )

Или вы можете сделать так, чтобы python записал такой скрипт в файл с расширением .sh:

export SOMEVAR=a_value
cd /home/you/desired/directory
./desired_program_cmd

, а затем chmod +x и запустить его из любого места.

0 голосов
/ 13 сентября 2015

Как ответил Бенсон, но лучшее решение - создать простую функцию bash для сохранения аргументов:

upsert-env-var (){ eval $(python upsert_env_var.py $*); }

Вы можете делать с вашими аргументами все, что захотите в скрипте Python. Чтобы просто добавить переменную, используйте что-то вроде:

var = sys.argv[1]
val = sys.argv[2]
if os.environ.get(var, None):
    print "export %s=%s:%s" % (var, val, os.environ[var])
else:
    print "export %s=%s" % (var, val)

Использование:

upsert-env-var VAR VAL
...