환경이 수정 된 Python 하위 프로세스 / Popen


285

약간 수정 된 환경에서 외부 명령을 실행하는 것이 매우 일반적인 경우라고 생각합니다. 그게 내가하는 경향이 있습니다.

import subprocess, os
my_env = os.environ
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)

더 좋은 방법이 있다고 생각합니다. 괜찮아 보이나요?


10
또한 os.pathsep플랫폼에서 작동하는 경로에는 ":"대신 사용하는 것이 좋습니다. 참조 stackoverflow.com/questions/1499019/...
아 미트

8
@phaedrus 나는 그가 같은 경로를 사용하여 때 확실히 매우 관련이 아니에요 /usr/sbin:-)
드미트리 Ginzburg

답변:


405

내가 생각하는 os.environ.copy()현재 프로세스에 대한 os.environ을 수정하지 않을 경우 더 나은 :

import subprocess, os
my_env = os.environ.copy()
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)

>>> env = os.environ.copy >>> env [ 'foo'] = 'bar'역 추적 (가장 최근 호출) : <module>의 파일 "<stdin>", 라인 1, TypeError : 'instancemethod' 목적은 항목 할당을 지원하지 않습니다
user1338062

5
@ user1338062 실제 메서드 os.environ.copyenv변수에 할당하고 있지만 메서드 호출 결과를에 할당해야 os.environ.copy()합니다 env.
chown

4
환경 변수 분석은 실제로 호출 shell=True에서 사용하는 경우에만 작동합니다 subprocess.Popen. 이를 수행 할 경우 잠재적으로 보안 관련 사항이 있습니다.
danielpops

내부 subprocess.Popen (my_command, env = my_env)- "my_command"는 무엇입니까
avinash

@avinash- my_command실행 명령입니다. 예를 들어 /path/to/your/own/program또는 다른 "실행 가능"명령문 일 수 있습니다 .
kajakIYD

64

그것은 문제가 무엇인지에 달려 있습니다. 환경을 복제하고 수정하는 경우 한 가지 해결책은 다음과 같습니다.

subprocess.Popen(my_command, env=dict(os.environ, PATH="path"))

그러나 대체 된 변수는 유효한 파이썬 식별자이며, 가장 자주 사용되는 변수입니다 (영숫자 + 밑줄이 아닌 환경 변수 이름 또는 숫자로 시작하는 변수는 얼마나 자주 발생합니까?).

그렇지 않으면 다음과 같이 작성할 수 있습니다.

subprocess.Popen(my_command, env=dict(os.environ, 
                                      **{"Not valid python name":"value"}))

매우 이상한 경우 (환경 변수 이름에 제어 코드 또는 ASCII가 아닌 문자를 얼마나 자주 사용합니까?) 환경의 키는 bytes(python3에서) 해당 구문을 사용할 수도 없습니다.

여기에 사용 된 기술 (특히 첫 번째)이 환경의 키에 대한 이점은 일반적으로 유효한 파이썬 식별자이며 사전에 (코딩시) 알려져 있지만 두 번째 접근법에는 문제가 있습니다. 그렇지 않은 경우 다른 방법을 찾아야합니다 .


3
공감. 나는 당신이 쓸 수 있다는 것을 몰랐습니다 dict(mapping, **kwargs). 나는 그것이 또는라고 생각했다. 참고 : @Daniel Burke가 현재 허용되는 답변에서 제안한os.environ 대로 수정하지 않고 복사 하지만 답변은 더 간결합니다. Python 3.5 이상에서는 할 수도 있습니다 . pep 448 참조 . dict(**{'x': 1}, y=2, **{'z': 3})
jfs

1
이 답변은 두 개의 사전을 하나의 새로운 하나로 병합하는 더 좋은 방법 (그리고이 방법이 그렇게 좋지 않은 이유)을 설명합니다 : stackoverflow.com/a/26853961/27729
krupan

@krupan : 이 특정 사용 사례에 어떤 단점이 있습니까? (임의의 받아쓰기와 환경 복사 / 업데이트는 다른 작업입니다).
jfs

1
@krupan 모든 일반적인 경우는 환경 변수가 유효한 파이썬 식별자 일 것입니다. 이는 첫 번째 구문을 의미합니다. 이 경우 귀하의 반대 의견은 없습니다. 두 번째 경우 주된 이의 제기는 여전히 실패합니다.이 경우 키가 기본적으로 환경의 문자열이어야하기 때문에 문자열이 아닌 키에 대한 요점은 해당되지 않습니다.
skyking

@JFSebastian 당신은이 특정한 경우에이 기술이 훌륭하고 나 자신을 더 잘 설명해야한다는 것이 맞습니다. 사과드립니다. 나는이 기술을 취해 두 개의 임의의 사전을 병합하는 일반적인 경우에 적용하려는 (나 자신과 같은) 사람들을 돕기를 원했습니다.
krupan

24

원래 환경에서 정의되지 않은 것이 아니라 괜찮아 보이는 경우 my_env.get("PATH", '')대신에 사용할 수 있습니다 .my_env["PATH"]PATH


21

Python 3.5를 사용하면 다음과 같이 할 수 있습니다.

import os
import subprocess

my_env = {**os.environ, 'PATH': '/usr/sbin:/sbin:' + os.environ['PATH']}

subprocess.Popen(my_command, env=my_env)

여기서 우리는 가치 의 사본 os.environ과 재정의로 끝납니다 PATH.

PEP 448 (추가 포장 풀기 일반화) 로 가능했습니다 .

다른 예시. 기본 환경 (예 os.environ:)이 있고 기본값을 재정의하려는 dict 가있는 경우 다음 과 같이 표현할 수 있습니다.

my_env = {**os.environ, **dict_with_env_variables}

@avinash, 하위 프로세스를 확인하십시오 . "프로그램 인수 시퀀스 또는 단일 문자열"입니다.
skovorodkin

10

os.envrion 객체 등을 복사하지 않고 환경 변수를 임시로 설정하려면 다음을 수행하십시오.

process = subprocess.Popen(['env', 'RSYNC_PASSWORD=foobar', 'rsync', \
'rsync://username@foobar.com::'], stdout=subprocess.PIPE)

4

env 매개 변수는 사전을 승인합니다. os.environ을 가져 와서 (필요한 경우 dict 사본에 원하는 변수) 키를 추가하고에 매개 변수로 사용할 수 Popen있습니다.


새로운 환경 변수를 추가하려는 경우 가장 간단한 대답입니다. os.environ['SOMEVAR'] = 'SOMEVAL'
Andy Fraley

1

나는 이것이 한동안 대답되었다는 것을 알고 있지만, 환경 변수에 PATH 대신 PYTHONPATH를 사용하는 것에 대해 알고 싶은 점이 있습니다. 수정 된 환경을 다른 방식으로 처리하는 cronjobs로 파이썬 스크립트를 실행하는 방법에 대한 개요를 설명했습니다 ( 여기 참조 ). 나와 같은이 답변보다 조금 더 필요한 사람들에게는 도움이 될 것이라고 생각했습니다.


0

특정 상황에서 하위 프로세스에 필요한 환경 변수 만 전달하고 싶을 수도 있지만 일반적으로 올바른 아이디어가 있다고 생각합니다 (그 방법도 마찬가지입니다).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.