J'ai un fichier texte /etc/default/foo
qui contient une ligne:
FOO="/path/to/foo"
Dans mon script python, je dois faire référence à la variable FOO.
Quel est le moyen le plus simple de "source" le fichier /etc/default/foo
dans mon script python, comme je le ferais avec bash?
. /etc/default/foo
Vous pouvez utiliser execfile :
execfile("/etc/default/foo")
Mais sachez que cela évaluera le contenu du fichier tel quel dans la source de votre programme. C'est un danger potentiel pour la sécurité, à moins que vous ne puissiez pleinement faire confiance à la source.
Cela signifie également que le fichier doit être conforme à la syntaxe python (votre exemple de fichier est).
Juste pour donner une approche différente, notez que si votre fichier original est configuré en tant que
export FOO=/path/to/foo
Vous pouvez créer source /etc/default/foo; python myprogram.py
(ou . /etc/default/foo; python myprogram.py
) et dans myprogram.py
, toutes les valeurs exportées dans le fichier sourced sont visibles dans os.environ, par exemple.
import os
os.environ["FOO"]
Si vous savez avec certitude qu'il ne contient que des variables de style VAR="QUOTED STRING"
, comme ceci:
FOO="some value"
Ensuite, vous pouvez simplement faire ceci:
>>> with open('foo.sysconfig') as fd:
... exec(fd.read())
Ce qui vous amène:
>>> FOO
'some value'
(C'est effectivement la même chose que la solution execfile()
Suggérée dans l'autre réponse.)
Cette méthode a des implications importantes en matière de sécurité; si au lieu de FOO="some value"
votre fichier contenait:
os.system("rm -rf /")
Alors vous seriez en difficulté.
Alternativement, vous pouvez faire ceci:
>>> with open('foo.sysconfig') as fd:
... settings = {var: shlex.split(value) for var, value in [line.split('=', 1) for line in fd]}
Ce qui vous donne un dictionnaire settings
qui a:
>>> settings
{'FOO': ['some value']}
Cette ligne settings = {...}
utilise un compréhension du dictionnaire . Vous pouvez accomplir la même chose en quelques lignes supplémentaires avec une boucle for
et ainsi de suite.
Et bien sûr, si le fichier contient une extension de variable de style Shell telle que ${somevar:-value_if_not_set}
, cela ne fonctionnera pas (à moins d'écrire votre propre analyseur de variable de style Shell).
Gardez à l'esprit que si vous avez un fichier "texte" avec ce contenu qui porte l'extension .py, vous pouvez toujours faire:
import mytextfile
print(mytestfile.FOO)
Bien entendu, cela suppose que le fichier texte est syntaxiquement correct en ce qui concerne Python. Sur un projet sur lequel j'ai travaillé, nous avons fait quelque chose de similaire. A transformé certains fichiers texte en fichiers Python. Wacky mais peut-être mérite d'être considéré.
Il y a plusieurs façons de faire ce genre de chose.
Vous pouvez en effet import
le fichier en tant que module, à condition que les données qu'il contient correspondent à la syntaxe de python. Mais le fichier en question est un .py
dans le même répertoire que votre script, vous devez utiliser imp
(ou importlib
, selon votre version) comme ici .
Une autre solution (à ma préférence) peut consister à utiliser un format de données que toute bibliothèque python peut analyser (JSON me vient à l’esprit comme exemple).
/ etc/default/foo:
{"FOO":"path/to/foo"}
Et dans votre code python:
import json
with open('/etc/default/foo') as file:
data = json.load(file)
FOO = data["FOO"]
## ...
file.close()
De cette façon, vous ne risquez pas d'exécuter du code incertain ...
Vous avez le choix, selon ce que vous préférez. Si votre script génère automatiquement un fichier de données, il serait peut-être plus simple de conserver une syntaxe simple, telle que FOO="path/to/foo"
, et d'utiliser imp
.
J'espère que ça aide!
Même réponse que @jil cependant, cette réponse est spécifique à une version historique de Python.
En Python moderne (3.0+):
exec()
remplace execfile()
Voici mon approche: analyser moi-même le fichier bash et ne traiter que les lignes d’attribution de variables telles que:
FOO="/path/to/foo"
Voici le code:
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 __== '__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)
Jetez un coup d'œil à cet extrait:
Shell_vars = dict(parse_Shell_var(line) for line in f if '=' in line)
Cette ligne parcourt les lignes du script Shell et ne traite que les lignes qui ont le signe égal (pas une manière infaillible de détecter une affectation de variable, mais la plus simple). Ensuite, exécutez ces lignes dans la fonction parse_Shell_var
qui utilise shlex.split
pour gérer correctement les guillemets (ou leur absence). Enfin, les pièces sont assemblées dans un dictionnaire. La sortie de ce script est:
{'MOO': '/dont/have/a/cow', 'FOO': 'my variable foo', 'BAR': 'My variable bar'}
Voici le contenu de Shell_vars.sh :
FOO='my variable foo'
BAR="My variable bar"
MOO=/dont/have/a/cow
echo $FOO
Cette approche présente quelques avantages:
Cette approche n’est pas parfaite, elle a quelques limitations:
Il n'analyse pas correctement les valeurs qui reposent sur d'autres variables ou commandes. Cela signifie que les lignes telles que:
FOO=$BAR
FOO=$(pwd)