Эмуляция Bash 'source' в Python

У меня есть скрипт, который выглядит примерно так:

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 ?

80
задан Mogsdad 17 August 2015 в 17:49
поделиться

2 ответа

Проблема с вашим подходом в том, что вы пытаетесь интерпретировать сценарии bash. Сначала вы просто пытаетесь интерпретировать оператор экспорта. Затем вы замечаете, что люди используют расширение переменных. Позже люди будут помещать в свои файлы условные обозначения или обрабатывать замены. В конце концов, у вас будет полноценный интерпретатор сценариев 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 не работает с исходным init_env , или сам bash не может выполняться, или подпроцесс не может выполнить bash, или любой другой ошибки.

env -i в начале командной строки создает чистую среду. это означает, что вы получите переменные среды только из init_env . если вам нужна унаследованная системная среда, опустите env -i .

Подробнее читайте в документации по подпроцессу .

Примечание: это будет захватывать только переменные, установленные с помощью оператора export , поскольку env печатает только экспортированные переменные.

Наслаждайтесь.

Обратите внимание, что в документации Python говорится, что если вы хотите манипулировать средой, вы должны манипулировать os.environ напрямую вместо использования os.putenv () . Я считаю это ошибкой, но я отвлекся.

99
ответ дан 24 November 2019 в 09:55
поделиться

Вместо того, чтобы иметь в качестве источника сценария Python сценарий bash, было бы проще и элегантнее иметь источник сценария оболочки init_env , а затем запускать сценарий Python с измененным окружающая обстановка.

#!/bin/bash
source init_env
/run/python/script.py
20
ответ дан 24 November 2019 в 09:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: