Quá trình con Python / Popen với môi trường được sửa đổi


284

Tôi tin rằng việc chạy một lệnh bên ngoài với môi trường được sửa đổi một chút là trường hợp rất phổ biến. Đó là cách tôi có xu hướng làm điều đó:

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

Tôi đã có một cảm giác ruột rằng có một cách tốt hơn; trông nó có ổn không?


10
Cũng thích sử dụng os.pathsepthay vì ":" cho các đường dẫn hoạt động trên các nền tảng. Xem stackoverflow.com/questions/1499019/ khăn
amit

8
@phaedrus Tôi không chắc nó rất phù hợp khi anh ấy sử dụng các đường dẫn như /usr/sbin:-)
Dmitry Ginzburg

Câu trả lời:


403

Tôi nghĩ os.environ.copy()sẽ tốt hơn nếu bạn không có ý định sửa đổi os.envir cho quy trình hiện tại:

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.envir.copy >>> env ['foo'] = 'bar' TracBack (cuộc gọi gần đây nhất) đối tượng không hỗ trợ gán vật phẩm
user1338062

5
@ user1338062 Bạn đang chuyển nhượng phương pháp thực tế os.environ.copyđể envbiến nhưng bạn cần phải gán kết quả của cách gọi phương thức os.environ.copy()để env.
chown

4
Độ phân giải biến môi trường chỉ thực sự hoạt động nếu bạn sử dụng shell=Truetrong lệnh subprocess.Popengọi của mình . Lưu ý rằng có khả năng bảo mật có thể làm điều đó.
danielpops

Bên trong quy trình con.Popen (my_command, env = my_env) - "my_command" là gì
avinash

@avinash - my_commandchỉ là lệnh để chạy. Nó có thể là ví dụ /path/to/your/own/programhoặc bất kỳ câu lệnh "thực thi" nào khác.
kajakIYD

64

Điều đó phụ thuộc vào vấn đề là gì. Nếu nó nhân bản và sửa đổi môi trường, một giải pháp có thể là:

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

Nhưng điều đó phần nào phụ thuộc vào việc các biến được thay thế là các định danh python hợp lệ, mà chúng thường là nhất (bạn có thường chạy vào các tên biến môi trường không phải là chữ và số + gạch dưới hoặc các biến bắt đầu bằng một số không?).

Nếu không, bạn sẽ có thể viết một cái gì đó như:

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

Trong trường hợp rất kỳ lạ (bạn có thường xuyên sử dụng mã điều khiển hoặc ký tự không phải mã ascii trong tên biến môi trường không?) Rằng các khóa của môi trường là bytesbạn không thể (trên python3) thậm chí sử dụng cấu trúc đó.

Như bạn có thể thấy các kỹ thuật (đặc biệt là kỹ thuật đầu tiên) được sử dụng ở đây mang lại lợi ích cho các khóa của môi trường thông thường là các định danh python hợp lệ và cũng được biết trước (tại thời điểm mã hóa), cách tiếp cận thứ hai có vấn đề. Trong trường hợp đó không phải là trường hợp bạn có thể nên tìm cách tiếp cận khác .


3
nâng cao. Tôi không biết rằng bạn có thể viết dict(mapping, **kwargs). Tôi nghĩ đó là một trong hai. Lưu ý: nó sao chép os.environmà không sửa đổi nó như @Daniel Burke đề xuất trong câu trả lời hiện được chấp nhận nhưng câu trả lời của bạn ngắn gọn hơn. Trong Python 3.5+ bạn thậm chí có thể làm dict(**{'x': 1}, y=2, **{'z': 3}). Xem pep 448 .
jfs

1
Câu trả lời này giải thích một số cách tốt hơn (và tại sao cách này không tuyệt vời) để hợp nhất hai từ điển thành một từ mới: stackoverflow.com/a/26853961/27729
krupan

@krupan: bạn thấy bất lợi gì cho trường hợp sử dụng cụ thể này? (hợp nhất các ký tự tùy ý và sao chép / cập nhật môi trường là các nhiệm vụ khác nhau).
jfs

1
@krupan Trước hết, trường hợp thông thường là các biến môi trường sẽ là định danh python hợp lệ, có nghĩa là cấu trúc đầu tiên. Đối với trường hợp đó không có sự phản đối của bạn giữ. Đối với trường hợp thứ hai, sự phản đối chính của bạn vẫn không thành công: điểm về các khóa không phải là chuỗi không được áp dụng trong trường hợp này vì về cơ bản các khóa được yêu cầu phải là chuỗi trong môi trường.
bầu trời

@JFSebastian Bạn đã đúng rằng trong trường hợp cụ thể này, kỹ thuật này là tốt và tôi nên tự giải thích rõ hơn. Lời xin lỗi của tôi. Tôi chỉ muốn giúp đỡ những người (chẳng hạn như bản thân tôi), những người có thể đã bị cám dỗ sử dụng kỹ thuật này và áp dụng nó vào trường hợp chung là hợp nhất hai từ điển tùy ý (có một số câu trả lời, như câu trả lời tôi đã liên kết).
krupan

24

bạn có thể sử dụng my_env.get("PATH", '')thay vì my_env["PATH"]trong trường hợp PATHbằng cách nào đó không được xác định trong môi trường ban đầu, nhưng khác hơn là nó trông ổn.


20

Với Python 3.5, bạn có thể làm theo cách này:

import os
import subprocess

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

subprocess.Popen(my_command, env=my_env)

Ở đây chúng tôi kết thúc với một bản sao của os.environPATHgiá trị ghi đè .

Nó đã được thực hiện bởi PEP 448 (Tổng quát hóa giải nén bổ sung).

Một vi dụ khac. Nếu bạn có một môi trường mặc định (nghĩa là os.environ) và một lệnh bạn muốn ghi đè mặc định, bạn có thể diễn đạt nó như sau:

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

@avinash, hãy kiểm tra subprocess.Popen tài liệu. Đó là "một chuỗi các đối số chương trình hoặc một chuỗi khác".
skovorodkin

10

Để tạm thời đặt biến môi trường mà không phải sao chép đối tượng os.envrion, v.v., tôi làm điều này:

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

4

Tham số env chấp nhận một từ điển. Bạn có thể chỉ cần lấy os.envir, thêm một khóa (biến mong muốn của bạn) (vào một bản sao của dict nếu bạn phải) vào đó và sử dụng nó làm tham số Popen.


Đây là câu trả lời đơn giản nhất nếu bạn chỉ muốn thêm một biến môi trường mới. os.environ['SOMEVAR'] = 'SOMEVAL'
Andy Fraley

1

Tôi biết điều này đã được trả lời một thời gian, nhưng có một số điểm mà một số người có thể muốn biết về việc sử dụng PYTHONPATH thay vì PATH trong biến môi trường của họ. Tôi đã phác thảo một lời giải thích về việc chạy các kịch bản python với các cronjobs liên quan đến môi trường đã sửa đổi theo một cách khác ( tìm thấy ở đây ). Nghĩ rằng nó sẽ có ích cho những người, giống như tôi, chỉ cần nhiều hơn một chút so với câu trả lời này được cung cấp.


0

Trong một số trường hợp nhất định, bạn có thể chỉ muốn chuyển xuống các biến môi trường mà quy trình con của bạn cần, nhưng tôi nghĩ rằng bạn đã có ý tưởng chung nói chung (đó là cách tôi cũng làm như vậy).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.