繁体   English   中英

是否有任何模块可以读取Shell脚本?

[英]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,但是您也可以通过后处理来减少冗长的操作。 特别地, shlexexport foo="bar spam eggs"视为两个值: exportfoo="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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM