我正在用Python编写一个用于命令行应用程序的测试框架。应用程序将创建目录,在当前目录中调用其他shell脚本,并将在Stdout上输出。
我试图将{Python-SubProcess,CommandLine}组合视为等同于{Selenium,Browser}。第一个组件在第二个组件上播放,如果输出是预期的,则检查。我面临以下问题
以下是我正在运行的示例代码
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
但过程挂起或可能是我做错了。另外我如何“抓住”该子流程的输出,以便断言存在某些东西?
答案 0 :(得分:2)
subprocess.Popen
允许您在启动进程后继续执行。 Popen
对象公开wait()
,poll()
以及许多其他方法,以便在子进程运行时与子进程通信。这不是你需要的吗?
有关详细信息,请参阅Popen constructor和Popen
对象说明。
这是一个在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.stdin
,Popen.stdout
,Popen.stderr
)。如果可能,我强烈推荐第一个解决方案(使用communicate
)。
否则,您必须输入命令并等待一段时间才能获得所需的输出。您需要的是非阻塞读取,以避免在没有任何内容可读时挂起。 Here是如何使用线程模拟管道上的非阻塞模式的配方。对于这样一个微不足道的目的,代码是丑陋而奇怪的复杂,但这就是它的完成方式。
另一个选项可能是使用p.stdout.fileno()
进行select.select()
调用,但这不适用于Windows(在Windows select
上仅对源自WinSock的对象有效)。如果您不在Windows上,可以考虑使用它。
答案 1 :(得分:1)
您可能会发现Python sh库非常有用,而不是使用普通subprocess
:
以下是如何使用sh:
构建异步交互循环的示例http://amoffat.github.com/sh/tutorials/2-interacting_with_processes.html
解决此问题的另一个(旧)库是pexpect: