2016-04-30 31 views
5

Ho un file di testo /etc/default/foo che contiene una riga:come file "sorgente" in script python

FOO="/path/to/foo" 

Nel mio script python, ho bisogno di fare riferimento alla FOO variabile.

Qual è il modo più semplice per "indirizzare" il file /etc/default/foo nel mio script python, come farei in bash?

. /etc/default/foo 

risposta

6

Potreste usare execfile:

execfile("/etc/default/foo") 

ma tieni presente che questo può valutare il contenuto del file come è nel vostro sorgente del programma. È un potenziale pericolo per la sicurezza a meno che tu non possa fidarti completamente della fonte.

Significa anche che il file deve essere valido sintassi python (il file di esempio fornito è).

+0

bel lavoro svolta una risposta senza senso in quella giusta. – dbliss

+0

Ovviamente questa è una pessima idea, a meno che non si abbia il controllo completo sui dati di input (nel qual caso, provaci, suppongo). – larsks

+0

Non è una cattiva risposta (è * permesso *) ma i soliti avvertimenti dovrebbero essere lì. – Harlin

2

Se sa per certo che contenga solo VAR="QUOTED STRING" variabili di stile, come questo:

FOO="some value" 

allora si può solo fare questo:

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

Che si ottiene:

>>> FOO 
'some value' 

(Questo è effectiv ely la stessa cosa della soluzione suggerita nell'altra risposta)

Questo metodo ha implicazioni di sicurezza sostanziali; se invece di FOO="some value" tuo file conteneva:

os.system("rm -rf /") 

Poi si sarebbe nei guai.

In alternativa, si può fare questo:

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

Che si ottiene un dizionario settings che ha:

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

Che settings = {...} linea sta usando una dictionary comprehension. È possibile ottenere la stessa cosa in poche altre righe con un ciclo for e così via.

E, naturalmente, se il file contiene un'espansione di variabile in stile shell come ${somevar:-value_if_not_set}, questo non funzionerà (a meno che non si scriva il proprio parser di variabili stile shell).

1

Tenete presente che se si dispone di un "testo" file con questo contenuto che ha un .py come l'estensione del file, si può sempre fare:

import mytextfile 

print(mytestfile.FOO) 

Naturalmente, questo presuppone che il file di testo è sintatticamente corretto per quanto riguarda Python. In un progetto a cui ho lavorato abbiamo fatto qualcosa di simile a questo. Trasformato alcuni file di testo in file Python.Strambo ma forse degno di considerazione.

+0

Penso che per wacky intendiate "pratica generalmente accettata come si vede ad esempio nel meccanismo settings.py di Django per fare la configurazione"; questo ha anche i vantaggi che puoi fare calcoli semplici (o non così semplici) per costruire stringhe ecc. usando la stessa sintassi python del resto del tuo programma :-P – Foon

+0

Wacky per chi non lo sapesse ;-) – Harlin

1

Ci sono un paio di modi per fare questo genere di cose.

  • si può infatti import il file come un modulo, a patto che i dati che contiene corrisponde la sintassi di Python. Ma il file in questione è uno .py nella stessa directory del tuo script, o devi usare imp (o importlib, a seconda della versione) like here.

  • Un'altra soluzione (che è la mia preferenza) può essere quella di utilizzare un formato dati che può essere analizzato da qualsiasi libreria python (JSON mi viene in mente come esempio).

/etc/default/pippo:

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

E nel codice Python:

import json 

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

In questo modo, non si rischia di eseguire del codice incerta ...

Hai la scelta, a seconda di cosa preferisci. Se il tuo file di dati viene generato automaticamente da alcuni script, potrebbe essere più semplice mantenere una sintassi semplice come FOO="path/to/foo" e utilizzare imp.

Spero che sia d'aiuto!

2

solo per dare un approccio diverso, si noti che, se il file originale è configurato come

export FOO=/path/to/foo 

Si può fare source /etc/default/foo; python myprogram.py (o . /etc/default/foo; python myprogram.py) ed entro myprogram.py tutti i valori che sono stati esportati nel file di origine' sono visibile in os.environ, ad esempio

import os 
os.environ["FOO"] 
0

La soluzione

Ecco il mio approccio: analizzare il MYS file di bash linee di assegnazione elfo e il processo di variabili solo come ad esempio:

FOO="/path/to/foo" 

Ecco il codice:

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) 

Come Funziona

Date un'occhiata a questo frammento:

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

Questa riga scorre le righe nello script della shell, elabora solo quelle linee che hanno il segno di uguale (non un foo l-proof modo per rilevare l'assegnazione variabile, ma il più semplice). Quindi, esegui quelle linee nella funzione parse_shell_var che utilizza shlex.split per gestire correttamente le virgolette (o la loro mancanza). Infine, i pezzi sono assemblati in un dizionario. L'output di questo script è:

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

Ecco il contenuto della shell_vars.sh:

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

Discussione

Questo approccio ha un paio di vantaggi:

  • Non esegue il guscio (sia in bash o in Python), che evita qualsiasi effetto collaterale
  • Di conseguenza, è sicuro da utilizzare, anche se l'origine dello script della shell è sconosciuta
  • Gestisce correttamente i valori con o senza quot es

Questo approccio non è perfetto, ha alcune limitazioni:

  • Metodo di rilevamento assegnazione variabile (guardando la presenza del segno uguale) è primitivo e non accurata. Esistono modi per rilevare meglio queste righe, ma questo è l'argomento per un altro giorno
  • Non analizza correttamente i valori costruiti su altre variabili o comandi. Ciò significa che, fallirà per le linee quali:

    FOO=$BAR 
    FOO=$(pwd) 
    
Problemi correlati