Tengo un script que se parece a esto:
export foo=/tmp/foo
export bar=/tmp/bar
Cada vez que construyo, ejecuto 'source init_env' (donde init_env es el script anterior) para configurar algunas variables.
Para lograr lo mismo en Python, tenía este código ejecutándose,
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)
Pero luego alguien decidió que sería bueno agregar una línea como la siguiente al init_envarchivo:
export PATH="/foo/bar:/bar/foo:$PATH"
Obviamente, mi script de Python se vino abajo. Podría modificar el script de Python para manejar esta línea, pero luego se romperá más adelante cuando alguien presente una nueva función para usar en el init_envarchivo.
La pregunta es si hay una manera fácil de ejecutar un comando Bash y dejar que modifique mi os.environ.

Respuestas:
El problema con su enfoque es que está intentando interpretar scripts de bash. Primero intente interpretar la declaración de exportación. Entonces notas que la gente está usando expansión variable. Más adelante, la gente pondrá condicionales en sus archivos o procesará sustituciones. Al final, tendrá un intérprete de guiones bash completo con un millón de errores. No hagas eso.
Deje que Bash interprete el archivo por usted y luego recopile los resultados.
Puedes hacerlo así:
Asegúrese de manejar los errores en caso de que bash falle
source init_env, o el propio bash no se ejecute, o el subproceso no ejecute bash, o cualquier otro error.el
env -ial principio de la línea de comandos crea un ambiente limpio. eso significa que solo obtendrá las variables de entorno deinit_env. si desea el entorno del sistema heredado, omitaenv -i.Lea la documentación sobre el subproceso para obtener más detalles.
Nota: esto solo capturará las variables establecidas con la
exportdeclaración, ya queenvsolo imprime las variables exportadas.Disfrutar.
Tenga en cuenta que la documentación de Python dice que si desea manipular el entorno, debe manipular
os.environdirectamente en lugar de usaros.putenv(). Lo considero un error, pero estoy divagando.fuente
proc.stdout()los rendimientos de bytes, por lo que estaba recibiendo unTypeErrorsobreline.partition(). Convertir a cadena conline.decode().partition("=")resolvió el problema.['env', '-i', 'bash', '-c', 'source .bashrc && env']entregarme sólo las variables de entorno establecidas por el archivo rcUsando pepinillo:
Actualizado:
Esto usa json, subprocess y explícitamente usa / bin / bash (para soporte de ubuntu):
fuente
/bin/dash, que no conoce elsourcecomando. Para usarlo en Ubuntu, debe ejecutarlo/bin/bashexplícitamente, por ejemplo, usandopenv = subprocess.Popen(['/bin/bash', '-c', '%s && %s' %(source,dump)], stdout=subprocess.PIPE).stdout(esto usa elsubprocessmódulo más nuevo que debe importarse).En lugar de tener la fuente de la secuencia de comandos de Python en la secuencia de comandos de bash, sería más simple y elegante tener una fuente de secuencia de comandos de envoltura
init_envy luego ejecutar la secuencia de comandos de Python con el entorno modificado.fuente
bash --rcfile init_env -c ./script.pySe actualizó la respuesta de @ lesmana para Python 3. Observe el uso de
env -ique evita que se establezcan / restablezcan variables de entorno extrañas (potencialmente incorrectamente dada la falta de manejo de variables de env multilínea).fuente
Ejemplo que envuelve la excelente respuesta de @ Brian en una función:
Estoy usando esta función de utilidad para leer las credenciales de AWS y los archivos Docker .env con
include_unexported_variables=True.fuente