2016-04-30 4 views
5

У меня есть текстовый файл, который содержит /etc/default/foo одну строку:как файл «источник» в питона скрипт

FOO="/path/to/foo" 

В моем питон скрипт, мне нужно ссылаться на переменную FOO.

Каков самый простой способ «указать» файл /etc/default/foo в мой сценарий python, как и в bash?

. /etc/default/foo 

ответ

6

Вы можете использовать execfile:

execfile("/etc/default/foo") 

Но следует помнить, что это оценит содержимое файла, как это в ваш исходный код программы. Это потенциальная угроза безопасности, если вы не можете полностью доверять источнику.

Это также означает, что файл должен быть действительным синтаксисом python (данный файл примера).

+0

хорошей работы токарных нонсенс ответ на правильный. – dbliss

+0

Конечно, это, как правило, очень плохая идея, если у вас нет полного контроля над вашими входными данными (в этом случае, пойдите, я думаю). – larsks

+0

Это не плохой ответ (он * допустим), но обычные оговорки должны быть там. – Harlin

2

Если вы знаете наверняка, что он содержит только VAR="QUOTED STRING" переменные стиля, как это:

FOO="some value" 

Тогда вы можете просто сделать это:

>>> with open('foo.sysconfig') as fd: 
... exec(fd.read()) 

Который получает вас:

>>> FOO 
'some value' 

(Это эффект то же самое, что и решение execfile() , предложенное в другом ответе.)

Этот метод имеет существенные последствия для безопасности; если вместо FOO="some value" ваш файл содержал:

os.system("rm -rf /") 

Тогда вы будете в беде.

В качестве альтернативы, вы можете сделать это:

>>> with open('foo.sysconfig') as fd: 
... settings = {var: shlex.split(value) for var, value in [line.split('=', 1) for line in fd]} 

который получает вам словарь settings, который имеет:

>>> settings 
{'FOO': ['some value']} 

Это settings = {...} линия использует dictionary comprehension. Вы можете выполнить одно и то же в нескольких строках с помощью цикла for и т. Д.

И, конечно, если файл содержит расширение переменной shell-типа, например, ${somevar:-value_if_not_set}, тогда это не сработает (если только вы не напишете свой собственный синтаксический переменный переменный).

1

Имейте в виду, что если у вас есть «текст» файл с таким содержанием, которое имеет .py в качестве расширения файла, вы всегда можете сделать:

import mytextfile 

print(mytestfile.FOO) 

Конечно, это предполагает, что текстовый файл является синтаксически корректным в отношении Python. В проекте, над которым я работал, мы сделали что-то похожее на это. Повернул некоторые текстовые файлы в файлы Python.Необычный, но, возможно, заслуживающий внимания.

+0

Я думаю, что по-дурацки вы имеете в виду «общепринятую практику, как показано, например, в файле настроек Django settings.py для настройки»; это также дает преимущества, которые вы можете выполнить простые (или не так просто) вычисления для создания строк и т. д., используя тот же синтаксис python, что и остальная часть вашей программы: -P – Foon

+0

Неразумный непосвященному ;-) – Harlin

1

Есть несколько способов сделать такие вещи.

  • Вы можете действительно import файл как модуль, до тех пор, как данные, которые он содержит, соответствует синтаксису питона. Но либо файл, о котором идет речь, является .py в том же каталоге, что и ваш скрипт, либо вы должны использовать imp (или importlib, в зависимости от вашей версии) like here.

  • Другим решением (которое имеет мои предпочтения) может быть использование формата данных, который может анализировать любая библиотека python (например, JSON приходит на ум).

/и т.д./по умолчанию/Foo:

{"FOO":"path/to/foo"} 

А в коде Python:

import json 

with open('/etc/default/foo') as file: 
    data = json.load(file) 
    FOO = data["FOO"] 
    ## ... 
    file.close() 

Таким образом, вы не рискуете выполнить некоторый неопределенный код ...

У вас есть выбор, в зависимости от того, что вы предпочитаете. Если ваш файл данных автогенерируется каким-то скриптом, может быть проще сохранить простой синтаксис, например FOO="path/to/foo", и использовать imp.

Надеюсь, что это поможет!

2

Просто чтобы дать другой подход, обратите внимание, что если ваш исходный файл установки, как

export FOO=/path/to/foo 

Вы можете сделать source /etc/default/foo; python myprogram.py (или . /etc/default/foo; python myprogram.py) и в myprogram.py все значения, которые были экспортированы в соерсед»файле, видны в os.environ, например

import os 
os.environ["FOO"] 
0

Решение

Вот мой подход: разобрать Баш файл Мыс Эльф и процесс только переменные линии назначения, такие как:

FOO="/path/to/foo" 

Вот код:

import shlex 

def parse_shell_var(line): 
    """ 
    Parse such lines as: 
     FOO="My variable foo" 

    :return: a tuple of var name and var value, such as 
     ('FOO', 'My variable foo') 
    """ 
    return shlex.split(line, posix=True)[0].split('=', 1) 

if __name__ == '__main__': 
    with open('shell_vars.sh') as f: 
     shell_vars = dict(parse_shell_var(line) for line in f if '=' in line) 
    print(shell_vars) 

Как это работает

Посмотрите на этот фрагмент:

 shell_vars = dict(parse_shell_var(line) for line in f if '=' in line) 

Эта строка выполняет итерации по строкам в сценарии оболочки, обрабатывает только те строки, которые имеют знак равенства (а не foo l-proof способ обнаружения переменных, но самый простой). Затем запустите эти строки в функции parse_shell_var, которая использует shlex.split, чтобы правильно обрабатывать кавычки (или их отсутствие). Наконец, части собраны в словарь. Вывод этого сценария:

{'MOO': '/dont/have/a/cow', 'FOO': 'my variable foo', 'BAR': 'My variable bar'} 

Вот содержание shell_vars.ш:

FOO='my variable foo' 
BAR="My variable bar" 
MOO=/dont/have/a/cow 
echo $FOO 

Обсуждение

Этот подход имеет несколько преимуществ:

  • Он не выполняет оболочки (либо в баш или Python), что позволяет избежать любой побочный эффект
  • Следовательно, он безопасен в использовании, даже если источник сценария оболочки неизвестен
  • Он правильно обрабатывает значения с или без кавычек эс

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

  • Метод определения переменной назначения (путем поиска на наличие знака равенства) примитивна и не точны. Есть способы лучше определить эти строки, но это тема для другого дня.
  • Он неправильно анализирует значения, которые основаны на других переменных или командах. Это означает, что она не будет выполнена для линий, таких как:

    FOO=$BAR 
    FOO=$(pwd)