像命令行模拟器一样使用python子进程模块

时间:2013-03-04 15:56:36

标签: python subprocess

我正在用Python编写一个用于命令行应用程序的测试框架。应用程序将创建目录,在当前目录中调用其他shell脚本,并将在Stdout上输出。

我试图将{Python-SubProcess,CommandLine}组合视为等同于{Selenium,Browser}。第一个组件在第二个组件上播放,如果输出是预期的,则检查。我面临以下问题

  1. Popen构造接受命令并在该命令完成后返回。我想要的是这个过程的实时句柄,这样我就可以运行更多命令+验证,最后完成后关闭shell
  2. 我可以编写一些基础设施代码来实现这一点,因为我们有很多需要测试的命令行应用程序。
  3. 以下是我正在运行的示例代码

     p = subprocess.Popen("/bin/bash", cwd = test_dir)
     p.communicate(input = "hostname") --> I expect the hostname to be printed out
     p.communicate(input = "time") --> I expect current time to be printed out 
    

    但过程挂起或可能是我做错了。另外我如何“抓住”该子流程的输出,以便断言存在某些东西?

2 个答案:

答案 0 :(得分:2)

subprocess.Popen允许您在启动进程后继续执行。 Popen对象公开wait()poll()以及许多其他方法,以便在子进程运行时与子进程通信。这不是你需要的吗?

有关详细信息,请参阅Popen constructorPopen对象说明。

这是一个在Unix系统上运行Bash并执行命令的小例子:

from subprocess import Popen, PIPE
p = Popen (['/bin/sh'], stdout=PIPE, stderr=PIPE, stdin=PIPE)
sout, serr = p.communicate('ls\n')
print 'OUT:'
print sout
print 'ERR:'
print serr

UPD: communicate()等待进程终止。如果你不需要,你可以直接使用适当的管道,虽然这通常会给你相当丑陋的代码。

UPD2:您更新了问题。是的,您无法为单个流程调用communicate两次。您可以通过一次调用communicate来提供执行所需的所有命令,并检查整个输出,或使用管道(Popen.stdinPopen.stdoutPopen.stderr)。如果可能,我强烈推荐第一个解决方案(使用communicate)。

否则,您必须输入命令并等待一段时间才能获得所需的输出。您需要的是非阻塞读取,以避免在没有任何内容可读时挂起。 Here是如何使用线程模拟管道上的非阻塞模式的配方。对于这样一个微不足道的目的,代码是丑陋而奇怪的复杂,但这就是它的完成方式。

另一个选项可能是使用p.stdout.fileno()进行select.select()调用,但这不适用于Windows(在Windows select上仅对源自WinSock的对象有效)。如果您不在Windows上,可以考虑使用它。

答案 1 :(得分:1)

您可能会发现Python sh库非常有用,而不是使用普通subprocess

http://amoffat.github.com/sh/

以下是如何使用sh:

构建异步交互循环的示例

http://amoffat.github.com/sh/tutorials/2-interacting_with_processes.html

解决此问题的另一个(旧)库是pexpect:

http://www.noah.org/wiki/pexpect