Saya memiliki skrip yang terlihat seperti ini:
export foo=/tmp/foo
export bar=/tmp/bar
Setiap kali saya membangun, saya menjalankan 'source init_env' (di mana init_env adalah skrip di atas) untuk menyiapkan beberapa variabel.
Untuk mencapai hal yang sama dengan Python saya menjalankan kode ini,
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)
Tetapi kemudian seseorang memutuskan akan lebih baik untuk menambahkan baris seperti berikut ke init_env
file:
export PATH="/foo/bar:/bar/foo:$PATH"
Jelas skrip Python saya berantakan. Saya dapat memodifikasi skrip Python untuk menangani baris ini, tetapi kemudian akan rusak nanti ketika seseorang datang dengan fitur baru untuk digunakan dalam init_env
file.
Pertanyaannya adalah apakah ada cara mudah untuk menjalankan perintah Bash dan membiarkannya memodifikasi perintah saya os.environ
?
Jawaban:
Masalah dengan pendekatan Anda adalah Anda mencoba menafsirkan skrip bash. Pertama, Anda hanya mencoba menafsirkan pernyataan ekspor. Kemudian Anda melihat orang-orang menggunakan ekspansi variabel. Nanti orang akan menempatkan kondisional dalam file mereka, atau proses substitusi. Pada akhirnya Anda akan memiliki penerjemah skrip bash lengkap dengan trilyun bug. Jangan lakukan itu.
Biarkan Bash menafsirkan file untuk Anda dan kemudian mengumpulkan hasilnya.
Anda bisa melakukannya seperti ini:
#! /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))
Pastikan Anda menangani kesalahan jika bash gagal
source init_env
, atau bash itu sendiri gagal dijalankan, atau subproses gagal mengeksekusi bash, atau kesalahan lainnya.yang
env -i
pada awal baris perintah menciptakan lingkungan yang bersih. itu berarti Anda hanya akan mendapatkan variabel lingkungan dariinit_env
. jika Anda ingin lingkungan sistem yang diwariskan, hilangkanenv -i
.Baca dokumentasi tentang subproses untuk lebih jelasnya.
Catatan: ini hanya akan menangkap variabel yang disetel dengan
export
pernyataan, karenaenv
hanya mencetak variabel yang diekspor.Nikmati.
Perhatikan bahwa dokumentasi Python mengatakan bahwa jika Anda ingin memanipulasi lingkungan, Anda harus memanipulasi
os.environ
secara langsung daripada menggunakanos.putenv()
. Saya menganggap itu bug, tapi saya ngelantur.sumber
proc.stdout()
hasil byte, sehingga saya mendapatkanTypeError
padaline.partition()
. Mengonversi menjadi string denganline.decode().partition("=")
memecahkan masalah.['env', '-i', 'bash', '-c', 'source .bashrc && env']
untuk memberikan diri saya sendiri hanya variabel lingkungan yang ditetapkan oleh file rcMenggunakan acar:
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
Diperbarui:
Ini menggunakan json, subproses, dan secara eksplisit menggunakan / bin / bash (untuk dukungan ubuntu):
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
sumber
/bin/dash
, yang tidak tahusource
perintahnya. Untuk menggunakannya di Ubuntu, Anda harus menjalankannya/bin/bash
secara eksplisit, misalnya dengan menggunakanpenv = subprocess.Popen(['/bin/bash', '-c', '%s && %s' %(source,dump)], stdout=subprocess.PIPE).stdout
(ini menggunakansubprocess
modul yang lebih baru yang harus diimpor).Daripada memiliki sumber skrip Python Anda sebagai skrip bash, akan lebih sederhana dan lebih elegan untuk memiliki sumber skrip pembungkus
init_env
dan kemudian menjalankan skrip Python Anda dengan lingkungan yang dimodifikasi.#!/bin/bash source init_env /run/python/script.py
sumber
bash --rcfile init_env -c ./script.py
Memperbarui jawaban @ lesmana untuk Python 3. Perhatikan penggunaannya
env -i
yang mencegah variabel lingkungan asing disetel / disetel ulang (berpotensi salah karena kurangnya penanganan untuk variabel env multiline).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
sumber
Contoh membungkus jawaban bagus @ Brian dalam sebuah fungsi:
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())
Saya menggunakan fungsi utilitas ini untuk membaca kredensial aws dan file docker .env dengan
include_unexported_variables=True
.sumber