在 Python 中模拟 Bash ‘source’

2025-02-27 09:07:00
admin
原创
57
摘要:问题描述:我有一个如下所示的脚本:export foo=/tmp/foo export bar=/tmp/bar 每次构建时,我都会运行“source init_env”(其中 init_env 是上述脚本)来设置一些变量。为...

问题描述:

我有一个如下所示的脚本:

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


解决方案 1:

您的方法存在问题,因为您尝试解释 bash 脚本。首先,您只是尝试解释导出语句。但是当人们认为他们可以使用 bash 语法时,他们就会这样做。他们将使用变量扩展、条件、进程替换。最后,您将得到一个功能齐全的 bash 脚本解释器,其中有无数的错误。不要这样做。

让 Bash 为您解释文件,然后收集结果。

这是一个最简单的例子,说明如何做到这一点:

#! /usr/bin/env python

import os
import pprint
import shlex
import subprocess

command = shlex.split("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))

确保处理错误。请参阅此处了解如何:“subprocess.Popen” - 检查成功和错误

另请阅读有关subprocess的文档。

这将只捕获用export语句设置的变量,因为env只打印导出的变量。您可以添加set -a将所有变量视为导出。

command = shlex.split("bash -c 'set -a && source init_env && env'")
                                ^^^^^^

请注意,此代码不会处理多行变量。它也不会处理 bash 函数定义。


也许比在 python 内部调用 bash source 更好的方法是先让 bash source 文件,然后运行 ​​python 脚本

#!/bin/bash
source init_env
/path/to/python_script.py

这里 bash 将source init_env拥有 bash 的所有功能、优势和怪癖。python 脚本将继承更新的环境。

请注意,只有导出的变量才会被继承。你可以强制导出所有变量赋值set -a

#!/bin/bash
set -a
source init_env
/path/to/python_script.py

另一种方法是告诉用户他们严格地只能在key=value没有任何 bash 功能的情况下执行操作。然后使用 python configparser。

这具有init_env语法简单和经过严格测试的配置解析器的优点。但缺点是init_env不再像 bash 配置文件那样具有表现力。

解决方案 2:

使用 pickle:

import os, pickle
# For clarity, I moved this string out of the command
source = 'source init_env'
dump = '/usr/bin/python -c "import os,pickle;print pickle.dumps(os.environ)"'
penv = os.popen('%s && %s' %(source,dump))
env = pickle.loads(penv.read())
os.environ = env

更新:

这使用 json、subprocess,并明确使用 /bin/bash(用于 ubuntu 支持):

import os, subprocess as sp, json
source = 'source init_env'
dump = '/usr/bin/python -c "import os, json;print json.dumps(dict(os.environ))"'
pipe = sp.Popen(['/bin/bash', '-c', '%s && %s' %(source,dump)], stdout=sp.PIPE)
env = json.loads(pipe.stdout.read())
os.environ = env

解决方案 3:

init_env与使用 Python 脚本获取 bash 脚本的源代码相比,使用包装器脚本源代码然后使用修改后的环境运行 Python 脚本会更简单、更优雅。

#!/bin/bash
source init_env
/run/python/script.py

解决方案 4:

更新了@lesmana 对 Python 3 的回答。请注意,使用env -i它可防止设置/重置多余的环境变量(由于缺乏对多行环境变量的处理,可能会出现错误)。

import os, subprocess
if os.path.isfile("init_env"):
    command = 'env -i sh -c "source init_env && env"'
    for line in subprocess.getoutput(command).split("
"):
        key, value = line.split("=")
        os.environ[key]= value

解决方案 5:

将@Brian 的优秀答案包装在函数中的示例:

import json
import subprocess

# returns a dictionary of the environment variables resulting from sourcing a file
def env_from_sourcing(file_to_source_path, include_unexported_variables=False):
    source = '%ssource %s' % ("set -a && " if include_unexported_variables else "", file_to_source_path)
    dump = '/usr/bin/python -c "import os, json; print json.dumps(dict(os.environ))"'
    pipe = subprocess.Popen(['/bin/bash', '-c', '%s && %s' % (source, dump)], stdout=subprocess.PIPE)
    return json.loads(pipe.stdout.read())

我正在使用此实用函数读取 aws 凭证和 docker .env 文件include_unexported_variables=True

解决方案 6:

我发现的最佳解决方法是这样的:

  • 编写一个包装器 bash 脚本来调用你的 python 脚本

  • 在该 bash 脚本中,你可以在获取当前终端后获取或调用该脚本

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2974  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1836  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与管理过程中扮演着至关重要的角色。然而,在实际运行中,资源冲突是经常会遇到的难题。资源冲突可能导致项目进度延迟、成本增加以及产品质量下降等一系列问题,严重影响企业的效益与竞争力。因此,如何有效应对PLM系统中的资源冲突,成为众多企业关注的焦点。接下来,我们将详细探讨5...
plm项目管理系统   47  
  敏捷项目管理与产品生命周期管理(PLM)的融合,正成为企业在复杂多变的市场环境中提升研发效率、增强竞争力的关键举措。随着技术的飞速发展和市场需求的快速更迭,传统的研发流程面临着诸多挑战,而将敏捷项目管理理念融入PLM,有望在2025年实现研发流程的深度优化,为企业创造更大的价值。理解敏捷项目管理与PLM的核心概念敏捷项...
plm项目   47  
  模块化设计在现代产品开发中扮演着至关重要的角色,它能够提升产品开发效率、降低成本、增强产品的可维护性与可扩展性。而产品生命周期管理(PLM)系统作为整合产品全生命周期信息的关键平台,对模块化设计有着强大的支持能力。随着技术的不断发展,到 2025 年,PLM 系统在支持模块化设计方面将有一系列令人瞩目的技术实践。数字化...
plm软件   48  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用