2

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

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

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

这是我正在运行的示例代码

 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 

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

4

2 回答 2

2

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

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

这是一个如何使用 sh 构建异步交互循环的示例:

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

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

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

于 2013-03-04T17:18:34.750 回答
2

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

有关详细信息,请参阅Popen 构造函数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)。

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

另一种选择可能是使用p.stdout.fileno()for select.select()call,但这在 Windows 上不起作用(在 Windows 上select仅对源自 WinSock 的对象进行操作)。如果您不在 Windows 上,您可以考虑它。

于 2013-03-04T16:01:07.387 回答