다음과 같은 스크립트가 있습니다.
export foo=/tmp/foo
export bar=/tmp/bar
빌드 할 때마다 ‘source init_env'(init_env는 위의 스크립트 임)를 실행하여 일부 변수를 설정합니다.
Python에서 동일한 작업을 수행하기 위해이 코드를 실행했습니다.
reg = re.compile('export (?P<name>\w+)(\=(?P<value>.+))*')
for line in open(file):
m = reg.match(line)
if m:
name = m.group('name')
value = ''
if m.group('value'):
value = m.group('value')
os.putenv(name, value)
그러나 누군가 다음과 같은 줄을 init_env
파일 에 추가하는 것이 좋을 것이라고 결정했습니다 .
export PATH="/foo/bar:/bar/foo:$PATH"
분명히 내 Python 스크립트가 무너졌습니다. 이 줄을 처리하도록 Python 스크립트를 수정할 수 있지만 나중에 누군가 가 init_env
파일 에서 사용할 새로운 기능을 제시 하면 나중에 중단 됩니다.
문제는 Bash 명령을 실행하는 쉬운 방법이 있는지 여부입니다 os.environ
.
답변
접근 방식의 문제점은 bash 스크립트를 해석하려고한다는 것입니다. 먼저 export 문을 해석하려고합니다. 그런 다음 사람들이 변수 확장을 사용하고 있음을 알 수 있습니다. 나중에 사람들은 조건문을 파일에 넣거나 대체를 처리합니다. 결국 당신은 엄청난 버그를 가진 완전한 bash 스크립트 인터프리터를 갖게 될 것입니다. 그러지 마.
Bash가 파일을 해석하도록 한 다음 결과를 수집합니다.
다음과 같이 할 수 있습니다.
#! /usr/bin/env python
import os
import pprint
import shlex
import subprocess
command = shlex.split("env -i bash -c 'source init_env && env'")
proc = subprocess.Popen(command, stdout = subprocess.PIPE)
for line in proc.stdout:
(key, _, value) = line.partition("=")
os.environ[key] = value
proc.communicate()
pprint.pprint(dict(os.environ))
bash가 실패 source init_env
하거나 bash 자체가 실행되지 않거나 하위 프로세스가 bash를 실행하지 못하는 경우 또는 기타 오류 가 발생하는 경우 오류를 처리해야 합니다.
env -i
명령 행의 시작 부분에 깨끗한 환경을 만듭니다. 즉,에서 환경 변수 만 가져옵니다 init_env
. 상속 된 시스템 환경을 원하면 env -i
.
자세한 내용 은 하위 프로세스에 대한 설명서 를 참조하십시오.
참고 : 내 보낸 변수 만 인쇄 하므로 export
명령문으로 설정된 변수 만 캡처 env
합니다.
즐겨.
있습니다 파이썬 문서는 당신이 환경을 조작 할 경우 조작하는 것을 말한다 os.environ
사용하는 대신 직접 os.putenv()
. 나는 그것을 버그라고 생각하지만 나는 우회한다.
답변
피클 사용 :
import os, pickle
# For clarity, I moved this string out of the command
source = 'source init_env'
dump = '/usr/bin/python -c "import os,pickle;print pickle.dumps(os.environ)"'
penv = os.popen('%s && %s' %(source,dump))
env = pickle.loads(penv.read())
os.environ = env
업데이트 :
이것은 json, 하위 프로세스를 사용하고 명시 적으로 / bin / bash를 사용합니다 (우분투 지원을 위해).
import os, subprocess as sp, json
source = 'source init_env'
dump = '/usr/bin/python -c "import os, json;print json.dumps(dict(os.environ))"'
pipe = sp.Popen(['/bin/bash', '-c', '%s && %s' %(source,dump)], stdout=sp.PIPE)
env = json.loads(pipe.stdout.read())
os.environ = env
답변
Python 스크립트가 bash 스크립트를 소스로 사용하는 것보다 래퍼 스크립트 소스를 init_env
보유한 다음 수정 된 환경에서 Python 스크립트를 실행 하는 것이 더 간단하고 우아 합니다.
#!/bin/bash
source init_env
/run/python/script.py
답변
Python 3에 대한 @lesmana의 답변을 업데이트했습니다. env -i
외부 환경 변수가 설정 / 재설정되는 것을 방지 하는 사용에 유의하십시오 (여러 줄 환경 변수에 대한 처리가 부족하여 잠재적으로 잘못됨).
import os, subprocess
if os.path.isfile("init_env"):
command = 'env -i sh -c "source init_env && env"'
for line in subprocess.getoutput(command).split("\n"):
key, value = line.split("=")
os.environ[key]= value
답변
함수에서 @Brian의 훌륭한 대답을 감싸는 예 :
import json
import subprocess
# returns a dictionary of the environment variables resulting from sourcing a file
def env_from_sourcing(file_to_source_path, include_unexported_variables=False):
source = '%ssource %s' % ("set -a && " if include_unexported_variables else "", file_to_source_path)
dump = '/usr/bin/python -c "import os, json; print json.dumps(dict(os.environ))"'
pipe = subprocess.Popen(['/bin/bash', '-c', '%s && %s' % (source, dump)], stdout=subprocess.PIPE)
return json.loads(pipe.stdout.read())
이 유틸리티 함수를 사용하여 .NET을 사용하여 aws 자격 증명 및 docker .env 파일을 읽고 있습니다 include_unexported_variables=True
.