1. ホーム
  2. python

[解決済み] PythonでBashの'source'をエミュレートする

2022-12-15 01:37:04

質問

以下のようなスクリプトがあります。

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 ?

どのように解決するのですか?

あなたのアプローチの問題は、bashスクリプトを解釈しようとしていることです。まず、export ステートメントを解釈しようとするだけです。それから、人々が変数展開を使用していることに気づきます。その後、人々はファイルに条件分岐を入れたり、置換を処理したりするようになります。最終的には、バグだらけのbashスクリプトインタプリタが完成します。そんなことはしないでください。

Bashにファイルを解釈させ、その結果を収集する。

こんな感じでできます。

#! /usr/bin/env python

import os
import pprint
import shlex
import subprocess

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

bashが失敗した場合のエラーを処理することを確認してください。 source init_env に失敗した場合、bash自体の実行に失敗した場合、サブプロセスがbashの実行に失敗した場合、その他のエラーに対処してください。

env -i はクリーンな環境を作ります。つまり、環境変数は init_env もし、システム環境を継承したい場合は env -i .

のドキュメントを読んでください。 サブプロセス のドキュメントを読んでください。

注意: これは export ステートメントで設定された変数のみを捕捉します。 env はエクスポートされた変数のみを表示します。

お楽しみに。

なお、この Python ドキュメント には、環境を操作したい場合は os.environ を使うのではなく、直接 os.putenv() . 私はそれをバグだと考えていますが、余談です。