亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

運行子進程后如何獲取環境變量

運行子進程后如何獲取環境變量

繁星coding 2023-07-11 15:00:04
我正在使用subprocess.call來執行來自我正在集成的另一個應用程序的 shell 腳本。該腳本使用export MY_VAR=foo. 接下來,我需要使用 shell 腳本設置的環境在子進程上執行更多命令。如何從子進程中提取環境狀態?它僅返回errno代碼。即我想運行:subprocess.call(["export", "MY_VAR=foo"] subprocess.call(["echo", "$MY_VAR"])  # should print 'foo'.我知道我可以使用env關鍵字設置環境,但我的問題是如何獲取子進程設置的環境變量。在 shell 中,您可以使用source任何腳本來獲取其聲明的環境變量。python 中的替代方案是什么?
查看完整描述

3 回答

?
一只萌萌小番薯

TA貢獻1795條經驗 獲得超7個贊

我最近遇到了這個問題。由于Python上游的原因,這似乎是一個難題:posix_spawn沒有提供讀取生成進程的環境變量的方法,也沒有任何簡單的方法來讀取正在運行的進程的環境。

Bashsource專門用于在 bash 解釋器中運行 bash 代碼:它只是在當前 bash 解釋器中評估文件,而不是啟動子進程。如果您從 Python 運行 bash 代碼,則此機制無法工作。

可以創建一個專門用于從 Python 運行 bash 代碼的單獨機制。以下是我能做到的最好的。如果有一個不那么脆弱的解決方案就好了。

import json

import os

import subprocess

import sys


from contextlib import AbstractContextManager



class BashRunnerWithSharedEnvironment(AbstractContextManager):

? ? """Run multiple bash scripts with persisent environment.


? ? Environment is stored to "env" member between runs. This can be updated

? ? directly to adjust the environment, or read to get variables.

? ? """


? ? def __init__(self, env=None):

? ? ? ? if env is None:

? ? ? ? ? ? env = dict(os.environ)

? ? ? ? self.env: Dict[str, str] = env

? ? ? ? self._fd_read, self._fd_write = os.pipe()


? ? def run(self, cmd, **opts):

? ? ? ? if self._fd_read is None:

? ? ? ? ? ? raise RuntimeError("BashRunner is already closed")

? ? ? ? write_env_pycode = ";".join(

? ? ? ? ? ? [

? ? ? ? ? ? ? ? "import os",

? ? ? ? ? ? ? ? "import json",

? ? ? ? ? ? ? ? f"os.write({self._fd_write}, json.dumps(dict(os.environ)).encode())",

? ? ? ? ? ? ]

? ? ? ? )

? ? ? ? write_env_shell_cmd = f"{sys.executable} -c '{write_env_pycode}'"

? ? ? ? cmd += "\n" + write_env_shell_cmd

? ? ? ? result = subprocess.run(

? ? ? ? ? ? ["bash", "-ce", cmd], pass_fds=[self._fd_write], env=self.env, **opts

? ? ? ? )

? ? ? ? self.env = json.loads(os.read(self._fd_read, 5000).decode())

? ? ? ? return result


? ? def __exit__(self, exc_type, exc_value, traceback):

? ? ? ? if self._fd_read:

? ? ? ? ? ? os.close(self._fd_read)

? ? ? ? ? ? os.close(self._fd_write)

? ? ? ? ? ? self._fd_read = None

? ? ? ? ? ? self._fd_write = None

? ??

? ? def __del__(self):

? ? ? ? self.__exit__(None, None, None)


例子:


with BashRunnerWithSharedEnvironment() as bash_runner:

? ? bash_runner.env.pop("A", None)


? ? res = bash_runner.run("A=6; echo $A", stdout=subprocess.PIPE)

? ? assert res.stdout == b'6\n'

? ? assert bash_runner.env.get("A", None) is None


? ? bash_runner.run("export A=2")

? ? assert bash_runner.env["A"] == "2"


? ? res = bash_runner.run("echo $A", stdout=subprocess.PIPE)

? ? assert res.stdout == b'2\n'


? ? res = bash_runner.run("A=6; echo $A", stdout=subprocess.PIPE)

? ? assert res.stdout == b'6\n'

? ? assert bash_runner.env.get("A", None) == "6"



? ? bash_runner.env["A"] = "7"

? ? res = bash_runner.run("echo $A", stdout=subprocess.PIPE)

? ? assert res.stdout == b'7\n'

? ? assert bash_runner.env["A"] == "7"


查看完整回答
反對 回復 2023-07-11
?
浮云間

TA貢獻1829條經驗 獲得超4個贊

不確定我是否看到這里的問題。您只需要記住以下幾點:


每個啟動的子流程獨立于之前子流程中完成的任何設置

如果您想設置一些變量并使用它們,請在一個過程中完成這兩件事

setupVars.sh所以像這樣制作:


export vHello="hello"

export vDate=$(date)

export vRandom=$RANDOM

并printVars.sh像這樣:


#!/bin/bash

echo $vHello, $vDate, $vRandom

并使用以下命令使其可執行:


chmod +x printVars.sh

現在你的 Python 看起來像這樣:


import subprocess


subprocess.call(["bash","-c","source setupVars.sh; ./printVars.sh"])

輸出


hello, Mon Jul 12 00:32:29 BST 2021, 8615


查看完整回答
反對 回復 2023-07-11
?
嗶嗶one

TA貢獻1854條經驗 獲得超8個贊

這是不可能的,因為環境僅在子進程中改變。您可以從那里將其作為輸出返回到 STDOUT、STDERR - 但是一旦子進程終止,您就無法從中訪問任何內容。


# this is process #1

subprocess.call(["export", "MY_VAR=foo"]


# this is process #2 - it can not see the environment of process #1

subprocess.call(["echo", "$MY_VAR"])  # should print 'foo'.


查看完整回答
反對 回復 2023-07-11
  • 3 回答
  • 0 關注
  • 247 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號