簡體   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