[英]Are there any modules to read shell scripts?
I'm making a python script right now, and I need to use some environment variables which are set in a bash shell script. 我现在正在制作python脚本,我需要使用在bash shell脚本中设置的一些环境变量。
The bash script is something like: 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
Normally, I would just source this script in bash, then go do my builds. 通常,我只是在bash中获取此脚本,然后进行构建。 I'm trying to wrap python around the whole process to do some management of the output so I want to remove the manual
source ./this_script.sh
step. 我正在尝试将python包装在整个过程中,以对输出进行一些管理,因此我想删除手动
source ./this_script.sh
步骤。
What I want to do is read this script from python and then use os.environ
to set up the variables within it. 我想做的是从python读取此脚本,然后使用
os.environ
在其中设置变量。 (I know this will not affect the parent, but only the current running Python instance and that's fine) (我知道这不会影响父对象,只会影响当前正在运行的Python实例,这样就可以了)
So to make my work easier, I'm trying to find out are there any modules which can "parse" the bash script and make use of the environment variables found within? 为了使我的工作更轻松,我试图找出是否有任何模块可以“解析” bash脚本并利用其中的环境变量? Currently I'm doing this by hand and it's a bit of a pain.
目前,我正在手动执行此操作,这有点痛苦。
If no such module exists to do exactly what I want, is there a more pythonic (read: easier/shorter) way of manually parsing a file in general, right now I'm doing this: 如果没有这样的模块可以完全实现我想要的功能,那么一般情况下,是否存在更多的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
There is no module to do exactly what you want, but shlex
will do a lot of what you want. 没有模块可以完全满足您的需求,但是
shlex
您的许多需求。 In particular, it will get the quoting , etc. right without you having to worry about it (which is the hardest part of this), as well as skipping comments, etc. The only thing it won't do is handle the export
keywords. 特别是,它将得到正确的引号等,而您不必担心它(这是其中最难的部分)以及跳过注释等。它唯一不会做的就是处理
export
关键字。
The easy way around that is to preprocess: 解决这个问题的简单方法是进行预处理:
with open(fn) as f:
processed = f.read().replace('export ', '')
for line in shlex.split(processed):
var, _, value = line.partition('=')
os.environ[var] = val
It's a bit hackier, but you can also do it a bit less verbosely by post-processing. 它有点hacker,但是您也可以通过后处理来减少冗长的操作。 In particular,
shlex
will treat export foo="bar spam eggs"
as two values: export
and foo="bar spam eggs"
, and you can just skip the ones that == 'export'
, or where the partition finds nothing, or… For example: 特别地,
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
If you want to get fancier, you can construct a shlex
object and (a) drive the parser directly from the file, and (b) control the parsing at a finer-grained level. 如果您想变得更高级,可以构造一个
shlex
对象,并(a)直接从文件驱动解析器,并且(b)在更细粒度的级别控制解析。 However, I don't think that's necessary here. 但是,我认为这不是必需的。
Meanwhile, if you want to handle environment substitution (as the BUILDDIR=$PWD
implies), this won't magically take care of that for you. 同时,如果您要处理环境替换(如
BUILDDIR=$PWD
所暗示的),那么这将不会为您神奇地解决问题。 You can make configparser
do that for you with its ExtendedInterpolation
feature , but then you'll need to trick configparser
into handling shlex
syntax, at which point… why bother. 您可以使用它的
ExtendedInterpolation
功能使configparser
做到这一点,但是随后您将需要诱使configparser
处理shlex
语法,这时……何必麻烦。
You can of course do it manually by writing your own interpolator, but that's hard to get right. 当然,您可以通过编写自己的插值器来手动完成此操作,但这很难做到。 You need to know the shell's rules for why
$PWD-foo
is the same as ${PWD}-foo
, but $PWD_foo
is the same as ${PWD_foo}
, etc. 您需要了解为什么
$PWD-foo
与${PWD}-foo
,但是$PWD_foo
与${PWD_foo}
相同的shell规则。
A better solution at this point—assuming the script is actually safe to run—would be to actually use a shell to do it for you. 在这一点上,一个更好的解决方案(假设脚本实际上可以安全运行)将是实际上使用shell为您完成此操作。 For example:
例如:
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
Of course this will also override things like _=/usr/bin/env
, but probably not anything you care about. 当然,这也会覆盖
_=/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
I had the same problem, and based on the advice from abarnert, I decided to implement the solution as a subprocess call to a restricted bash shell, combined with shlex. 我遇到了同样的问题,并且根据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]
The advantage to the restricted shell is that it blocks many of the undesirable or malicious side effects that may otherwise happen when executing a shell script. 受限Shell的优点在于,它可以阻止执行Shell脚本时可能发生的许多不良或恶意副作用。 From the bash documentation:
从bash文档中:
A restricted shell is used to set up an environment more controlled than the standard shell.
受限外壳用于设置比标准外壳更受控制的环境。 It behaves identically to bash with the exception that the following are disallowed or not performed:
它的行为与bash相同,不同之处在于不允许或不执行以下操作:
- changing directories with cd
用cd更改目录
- setting or unsetting the values of SHELL, PATH, ENV, or BASH_ENV
设置或取消设置SHELL,PATH,ENV或BASH_ENV的值
- specifying command names containing /
指定包含/的命令名称
- specifying a file name containing a / as an argument to the .
指定一个包含/的文件名作为。 builtin command
内置命令
- Specifying a filename containing a slash as an argument to the -p option to the hash builtin command
将包含斜杠的文件名指定为hash内置命令的-p选项的参数
- importing function definitions from the shell environment at startup
启动时从外壳环境导入函数定义
- parsing the value of SHELLOPTS from the shell environment at startup
启动时从shell环境中解析SHELLOPTS的值
- redirecting output using the >, >|, <>, >&, &>, and >> redirection operators
使用>,> |,<>,>&,&>和>>重定向运算符重定向输出
- using the exec builtin command to replace the shell with another command
使用exec内置命令将外壳替换为另一个命令
- adding or deleting builtin commands with the -f and -d options to the enable builtin command
在启用内置命令中添加或删除带有-f和-d选项的内置命令
- Using the enable builtin command to enable disabled shell builtins
使用enable buildin命令启用禁用的shell内置程序
- specifying the -p option to the command builtin command
在命令内置命令中指定-p选项
- turning off restricted mode with set +r or set +o restricted.
使用设置+ r或设置+ o限制关闭受限模式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.