[英]Are there any modules to read shell scripts?
我现在正在制作python脚本,我需要使用在bash shell脚本中设置的一些环境变量。
bash脚本类似于:
#! /bin/sh
#sets some names:
export DISTRO="unified"
#export DISTRO="other"
#number of parallel builds
export BB_NUM_THREADS=2
#set build dir
export BUILDDIR=$PWD
通常,我只是在bash中获取此脚本,然后进行构建。 我正在尝试将python包装在整个过程中,以对输出进行一些管理,因此我想删除手动source ./this_script.sh
步骤。
我想做的是从python读取此脚本,然后使用os.environ
在其中设置变量。 (我知道这不会影响父对象,只会影响当前正在运行的Python实例,这样就可以了)
为了使我的工作更轻松,我试图找出是否有任何模块可以“解析” bash脚本并利用其中的环境变量? 目前,我正在手动执行此操作,这有点痛苦。
如果没有这样的模块可以完全实现我想要的功能,那么一般情况下,是否存在更多的pythonic(阅读:更容易/更简短)的方法来手动解析文件,现在我正在这样做:
def parse_bash_script(fn):
with open(fn) as f:
for line in f:
if not line[:1] == '#': #ignore comments
if "export" in line:
line = line.replace(" ","").strip()
var = line[6:line.find("=")]
val = line[line.find("=")+1:len(line)]
if "\"" in val:
val = val[1:-1]
os.environ[var]=val
没有模块可以完全满足您的需求,但是shlex
您的许多需求。 特别是,它将得到正确的引号等,而您不必担心它(这是其中最难的部分)以及跳过注释等。它唯一不会做的就是处理export
关键字。
解决这个问题的简单方法是进行预处理:
with open(fn) as f:
processed = f.read().replace('export ', '')
for line in shlex.split(processed):
var, _, value = line.partition('=')
os.environ[var] = val
它有点hacker,但是您也可以通过后处理来减少冗长的操作。 特别地, shlex
将export foo="bar spam eggs"
视为两个值: export
和foo="bar spam eggs"
,您可以跳过== 'export'
的分区,或者在分区找不到任何内容的地方,或者… 例如:
with open(fn) as f:
for line in shlex.split(f.read()):
var, eq, value = line.partition('=')
if eq:
os.environ[var] = val
如果您想变得更高级,可以构造一个shlex
对象,并(a)直接从文件驱动解析器,并且(b)在更细粒度的级别控制解析。 但是,我认为这不是必需的。
同时,如果您要处理环境替换(如BUILDDIR=$PWD
所暗示的),那么这将不会为您神奇地解决问题。 您可以使用它的ExtendedInterpolation
功能使configparser
做到这一点,但是随后您将需要诱使configparser
处理shlex
语法,这时……何必麻烦。
当然,您可以通过编写自己的插值器来手动完成此操作,但这很难做到。 您需要了解为什么$PWD-foo
与${PWD}-foo
,但是$PWD_foo
与${PWD_foo}
相同的shell规则。
在这一点上,一个更好的解决方案(假设脚本实际上可以安全运行)将是实际上使用shell为您完成此操作。 例如:
with open('script.sh') as f:
script = f.read()
script += b'\nenv'
with subprocess.Popen(['sh'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as p:
result = p.communicate(script)
for line in result.splitlines():
var, _, value = line.partition('=')
os.environ[var] = value
当然,这也会覆盖_=/usr/bin/env
东西,但可能与您无关。
def parse_bash_script(fn):
with open(fn) as f:
for line in f:
if not line.startswith('#'): #ignore comments
if "export" in line:
var, _, val = line.partition('=')
var = var.lstrip()
val = val.rstrip()
if val.startswith('"'):
vals = val.rpartition('"')
val = vals[0][1]+vals[2]
os.environ[var]=val
我遇到了同样的问题,并且根据abarnert的建议,我决定将解决方案作为对受限制的bash shell与shlex结合的子流程调用来实现。
import shlex
import subprocess
filename = '/path/to/file.conf'
o, e = subprocess.Popen(
['/bin/bash', '--restricted', '--noprofile', '--init-file',
filename, '-i', '-c', 'declare'],
env={'PATH': ''},
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()
if e:
raise StandardError('conf error in {}: {}'.format(filename, e))
for token in shlex.split(o):
parts = token.split('=', 1)
if len(parts) == 2:
os.environ[parts[0]] = parts[1]
受限Shell的优点在于,它可以阻止执行Shell脚本时可能发生的许多不良或恶意副作用。 从bash文档中:
受限外壳用于设置比标准外壳更受控制的环境。 它的行为与bash相同,不同之处在于不允许或不执行以下操作:
- 用cd更改目录
- 设置或取消设置SHELL,PATH,ENV或BASH_ENV的值
- 指定包含/的命令名称
- 指定一个包含/的文件名作为。 内置命令
- 将包含斜杠的文件名指定为hash内置命令的-p选项的参数
- 启动时从外壳环境导入函数定义
- 启动时从shell环境中解析SHELLOPTS的值
- 使用>,> |,<>,>&,&>和>>重定向运算符重定向输出
- 使用exec内置命令将外壳替换为另一个命令
- 在启用内置命令中添加或删除带有-f和-d选项的内置命令
- 使用enable buildin命令启用禁用的shell内置程序
- 在命令内置命令中指定-p选项
- 使用设置+ r或设置+ o限制关闭受限模式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.