Python alt süreci / Değiştirilmiş bir ortamla pop


285

Harici bir komutun biraz değiştirilmiş bir ortamla çalıştırılmasının çok yaygın bir durum olduğuna inanıyorum. Bunu şu şekilde yapmaya eğilimliyim:

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

Daha iyi bir yol olduğuna dair bir his var; iyi görünüyor mu?


10
Ayrıca os.pathsep, platformlarda çalışan yollar için ":" yerine kullanmayı tercih edin . Bkz. Stackoverflow.com/questions/1499019/…
amit

8
@phaedrus /usr/sbin:-) gibi yolları kullandığında çok alakalı olduğundan emin değilim
Dmitry Ginzburg

Yanıtlar:


405

os.environ.copy()Geçerli işlem için os.environ üzerinde değişiklik yapmak istemiyorsanız daha iyi olduğunu düşünüyorum :

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' Geri izleme (son çağrı son): <module> TypeError: 'instancemethod' dosyasında "<stdin>", satır 1 nesnesi öğe atamasını desteklemiyor
user1338062

5
@ user1338062 Sen gerçek yöntemini atamayacaksanız os.environ.copyiçin envdeğişken ancak yöntemini çağırarak sonucunu atamanız gerekir os.environ.copy()için env.
chown

4
Eğer kullanırsanız ortam değişkeni çözünürlüğü sadece gerçekten çalışıyor shell=Truesenin içinde subprocess.Popençağırma. Bunu yapmanın potansiyel güvenlik etkileri olabileceğini unutmayın.
danielpops

Alt süreç içinde.Popen (my_command, env = my_env) - "my_command" nedir
avinash

@avinash - my_commandsadece çalıştırmak için komuttur. Örneğin /path/to/your/own/programveya başka bir "yürütülebilir" deyim olabilir.
kajakIYD

64

Bu, sorunun ne olduğuna bağlıdır. Çevreyi klonlamak ve değiştirmek için bir çözüm olabilir:

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

Ancak bu, değiştirilen değişkenlerin en sık oldukları geçerli python tanımlayıcılarına bağlı olmasına bağlıdır (ne sıklıkla alfasayısal + alt çizgi olmayan veya bir sayı ile başlayan değişkenler?

Aksi takdirde şöyle bir şey yazabilirsiniz:

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

Çok tuhaf durumda (ortam değişken isimlerinde kontrol kodlarını veya ascii olmayan karakterleri ne sıklıkta kullanıyorsunuz?) bytes, Ortamın anahtarlarının (python3'te) bu yapıyı bile kullanamayacağınız.

Gördüğünüz gibi burada kullanılan teknikler (özellikle ilk olarak) ortamın anahtarları üzerindeki faydalar normalde geçerli python tanımlayıcılarıdır ve önceden (kodlama zamanında) da bilinir, ikinci yaklaşımın sorunları vardır. Durumun böyle olmadığı durumlarda, muhtemelen başka bir yaklaşım aramalısınız .


3
upvote. Yazabileceğini bilmiyordum dict(mapping, **kwargs). Ben de öyle ya da diye düşündüm. Not: Şu anda kabul edilen cevapta @Daniel Burke tarafından önerilenos.environ şekilde değiştirmeden kopyalar , ancak cevabınız daha özlüdür. Python 3.5 ve üzeri sürümlerde bile yapabilirsiniz . Bakınız pep 448 . dict(**{'x': 1}, y=2, **{'z': 3})
jfs

1
Bu yanıt, iki sözlüğü yeni bir
tanesiyle

@krupan: Bu özel kullanım durumu için hangi dezavantajı görüyorsunuz ? (keyfi dikimleri birleştirmek ve ortamı kopyalamak / güncellemek farklı görevlerdir).
jfs

1
@krupan Her şeyden önce, ortam değişkenlerinin geçerli python tanımlayıcıları olması, yani ilk yapı anlamına gelir. Bu durumda itirazlarınızın hiçbiri geçerli değil. İkinci durumda ana itirazınız hala başarısız olur: Bu durumda dize olmayan tuşlarla ilgili nokta, anahtarların temelde ortamdaki dizeler olması gerektiği için geçerli değildir.
35'te skyking

@JFSebastian Bu özel durum için bu tekniğin iyi olduğunu ve kendimi daha iyi açıklamam gerektiğini doğru söylüyorsunuz. Özür dilerim. Ben sadece bu tekniği almaya cazip gelmiş olanlara (kendim gibi) yardım etmek istedim ve iki keyfi sözlüğü (ki bazı işaretler var, işaret ettiğim cevap olarak) birleştirmenin genel durumuna uyguladım.
krupan

24

Eğer kullanabilir my_env.get("PATH", '')yerine my_env["PATH"]durumunda PATHbu cezayı göründüğünden daha her nasılsa orijinal ortamda tanımlanmamış, ancak diğer.


21

Python 3.5 ile bunu şu şekilde yapabilirsiniz:

import os
import subprocess

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

subprocess.Popen(my_command, env=my_env)

Burada değerin bir kopyası os.environve geçersiz kılınmasıyla sonuçlanır PATH.

Bu ile mümkün olmuştur PEP 448 (Ek Paketten Çıkarma Genellemeler).

Başka bir örnek. Varsayılan bir ortamınız varsa (yani os.environ) ve varsayılanları geçersiz kılmak istediğiniz bir diktüre sahipseniz, bunu şu şekilde ifade edebilirsiniz:

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

@avinash, alt süreci kontrol edin . "Bir dizi program argümanı veya tek bir dize".
skovorodkin

10

Os.envrion nesnesini vb. Kopyalamak zorunda kalmadan geçici olarak bir ortam değişkeni ayarlamak için şunu yaparım:

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

4

Env parametresi bir sözlüğü kabul eder. Sadece os.environ'ı alabilir, buna bir anahtar (istediğiniz değişken) (eğer gerekiyorsa, diktenin bir kopyasına) ekleyebilir ve bunu bir parametre olarak kullanabilirsiniz Popen.


Yeni bir ortam değişkeni eklemek istiyorsanız bu en basit cevaptır. os.environ['SOMEVAR'] = 'SOMEVAL'
Andy Fraley

1

Bunun bir süredir yanıtlandığını biliyorum, ancak bazılarının ortam değişkenlerinde PATH yerine PYTHONPATH kullanımı hakkında bilmek isteyebilecekleri bazı noktalar var. Ben değiştirilmiş ortam ( burada bulundu ) ile ilgilenen cronjobs ile python komut dosyalarını çalıştırma bir açıklama özetledim . Benim gibi bu cevaptan biraz daha fazlasına ihtiyaç duyanlar için iyi olacağını düşündüm.


0

Bazı durumlarda yalnızca alt işleminizin ihtiyaç duyduğu ortam değişkenlerini aktarmak isteyebilirsiniz, ancak genel olarak doğru fikre sahip olduğunuzu düşünüyorum (ben de öyle yapıyorum).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.