【问题标题】:Run multiple bash lines in Python and separetely check their status and output在 Python 中运行多个 bash 行并分别检查它们的状态和输出
【发布时间】:2019-06-17 22:16:57
【问题描述】:

我正在尝试在 Python 3 中执行几行 bash 并分别检查每一行的状态。

我首先尝试使用subprocess 中的gestatusoutput,但是每一行都在一个不与其他行通信的单独进程中运行(为了简单起见,给定的 MWE 包括设置一个变量,但是什么我打算在我的实际代码中做的比这更复杂——我知道os.environ 这个非常具体的例子):

from subprocess import getstatusoutput as cmd

stat, out = cmd("export TEST=1")
stat, out = cmd("echo $TEST")

将因此返回:

>>> print(out)
(0, "")

然后我尝试了以下方法:

cmdline = """export TEST=1
echo $TEST"""
stat, out = cmd(cmdline)

这可行,但迫使我解析输出,特别是如果我想检查第一个命令的状态(如果echo 有效,则cmd 返回的状态是0 无论之前发生什么),即不是很健壮。

我看到了一些使用Popen(仍然来自subprocess)的东西,但无法有效地使用它。

任何帮助将不胜感激!

【问题讨论】:

  • 如果要执行多个命令并处理它们的所有输出,则需要对其进行解析。没有自动方法知道每个命令的输出在哪里结束。
  • 您可以在每个命令之间添加echo 'XXXXX' 之类的内容,并将其用作分隔符。
  • 在我看来,必须有一种方法可以使用相同的进程 ID,因此必须在一致的上下文中执行操作,而无需求助于解析输出。
  • 或许可以考虑使用pexpect,这样您就可以“控制”其他进程并响应其输出...pexpect.readthedocs.io/en/stable/index.html
  • @MBR 你确定你需要使用 shell 命令吗?您可以在 shell 中执行的大多数操作也可以直接在 Python 中完成。你想做什么需要这种复杂的外壳处理?

标签: python python-3.x bash subprocess


【解决方案1】:

对我来说,您试图在两个进程之间共享环境变量,这是不可能的。 它看起来像这样:

Process 1 python main.py                #TEST = "" 
    |Process 2-->"export TEST=1"        #Change Process2 env variable TEST to '1'
    |Process 3-->"echo $TEST"           #Print Process3 env variable TEST (get from process 1)

可以先用os.environ[]改变当前环境(进程1变量),再用fork后的变量。

类似的东西

import os
import subprocess
import sys

os.environ['TEST'] = '1'
out = subprocess.check_call('echo $TEST',shell = True)

【讨论】:

  • 感谢您的回答,但它并不能满足我的需要,因为为了简单起见,我给出了这个例子。我打算在我的实际代码中做的比仅仅设置一个变量更复杂。
【解决方案2】:

我做了以下事情:

  • 创建一个 launch 命令包装 subprocess.Popen 来启动我的 bash 命令,此外还允许我检索当前环境或传递自定义环境
  • 创建一个get_env 来解析上一个命令的返回,并得到一个环境的dict

launch 包装器

import os
import subprocess as sp

def launch(cmd_, env=os.environ, get_env=False):
    if get_env: cmd_ += " && printenv"
    load = sp.Popen(cmd_, shell=True, stdout=sp.PIPE, stderr=sp.PIPE, env=env)
    out  = load.communicate()
    err  = load.returncode
    return(err, out)

检索环境

def get_env(out, encoding='utf-8'):
    lout = str(out[0], encoding).split('\n')
    new_env = {}
    for line in lout:
        if len(line.split('=')) <= 1:
            pass
        else:
            k = line.split("=")[0]
            v = "=".join(line.split("=")[1:])
            new_env[k] = v
    return new_env

(这是一个简单的版本,如果你的环境中有函数之类的东西,它可能会更复杂——它会发生。)


结果:

我可以如下使用它:

err, out = launch("export TEST=1", get_env=True)
if not err: new_env = get_env(out)
err, out = launch("echo $TEST", env=new_env)

因此:

>>> print(str(out[0], encoding='utf-8'))
1

【讨论】:

    猜你喜欢
    • 2017-07-05
    • 2016-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-19
    • 2021-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多