具有预先填充环境的Python子进程模块

时间:2013-03-05 10:14:29

标签: python python-2.7 subprocess

问题可能与Use python subprocess module like a command line simulator

有关

我已经写了一些名为my_shell的基础设施代码,你可以传递我的应用程序的shell命令,看起来像这样

class ApplicationTestShell(object):
    def __init__(self):
        '''
        Constructor
        '''
        self.play_ground_dir = "/var/tmp/MyAppDir" 
        ensure_dir_exists_and_empty(self.play_ground_dir)

    def execute_command(self, command, on_success = None, on_failure = None):
        p = create_shell_process(self, self.play_ground_dir)
        sout, serr = p.communicate(input = command)
        if p.returncode == 0:
            on_success(sout)
        else:
            on_failure(serr)

    def create_shell_process(self, cwd):
        return Popen("/bin/bash", env= {WHAT DO I DO HERE?},cwd = test_dir, stdout=PIPE, stderr=PIPE, stdin=PIPE)

这里有趣的是env参数。 Python期望像所有环境变量的“map”数据结构。我的应用程序需要导出和设置多个变量。设置和导出的脚本是通过运行说'/ bin / appload myapp'生成的(假设appload始终在路径上可用)。我现在做什么 当我打电话给p.communicate时,我会做以下

p.communicate(input = "eval `/bin/appload myapp`;" + command)

所以基本上在运行命令之前我称之为基础架构设置。

  1. 有没有办法在Python中以更好的方式做到这一点。我想以某种方式将eval / bin / appload部分推送到Popen类的env参数或作为shell创建过程的一部分。
  2. 我目前的实施有什么问题? (我觉得这很黑,但我可能错了)

1 个答案:

答案 0 :(得分:1)

  1. 这取决于/bin/appload myapp的工作原理。如果它只保证它将输出bash语法,那么在Python中解析该输出以构造环境对象几乎肯定会有更多麻烦(你可能需要支持参数和变量扩展,子shell,进程替换等)等)。另一方面,如果您确定/bin/appload myapp只会输出“VARIABLENAME=someword”形式的行,那么在Python中解析这一点非常简单,如果您将它移动到Python代码中等。

    你可以根据这些要求提出许多不同的指示;您可以将appload myapp的输出捕获到临时文件中,并将子进程的$BASH_ENV设置为该文件名;这会导致shell在以某些人认为更干净的方式运行命令之前获取环境设置。您可以将命令(使用eval - 前缀)作为Popen的第一个参数并传递shell=True,然后让Popen执行bash调用单独(如有必要,明确设置$SHELL bash)。您可以使用bash的-c选项指定要在命令行上运行的代码,而不是通过stdin。您可以通过从Python调用一个shell来进行多层方法,其中eval是appload myapp环境,然后是exec的另一个shell,因此第一个没有出现在ps列表中,并且命令给了{{ 1}}有自己的shell(虽然这应该不重要)。您可以做很多事情,具体取决于您对shell调用方式的关注点,它在ps列表中的外观,是否希望在create_shell_process输出产生错误时仍然运行命令当评估时,等等。但是对于一般解决方案,我认为你所拥有的是完全没问题的。

  2. 除了复制和粘贴代码之外的整容或小事之外,我没有看到任何实际的实施问题:appload myapp不使用其create_shell_process参数,cwdon_success参数看起来像是可选的,但默认值会破坏(您无法调用on_failure)。