it-swarm.com.ru

Почему переменные среды, установленные в python, не сохраняются?

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

Это правда?

а также

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

37
physicsmichael

Вы не можете сделать это из 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, которую вы запускаете. 

31
Benson

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

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)

17
dbr

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

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

в fooexport.sh

export FOO="bar"

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

$ . ./fooexport.sh
$ echo $FOO
bar
3
Stefano Borini

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

#!/bin/bash

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

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

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

myappenv dosometask -xyz

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

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

#!/bin/bash

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

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

2
Joe Holloway

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

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

Вы также можете сделать так, чтобы Python запустил программу симуляции с желаемой средой. (используйте параметр env для subprocess.Popen ( 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 и запустите его из любого места.

1
Joe Koberg

Как ответил Бенсон, но лучший способ обойти это - создать простую функцию 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
0
Niall