【问题标题】:Use python subprocess module like a command line simulator像命令行模拟器一样使用 python 子进程模块
【发布时间】:2013-03-04 15:56:35
【问题描述】:

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

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

  1. Popen 构造接受一个命令并在该命令完成后返回。我想要的是进程的实时句柄,这样我就可以运行进一步的命令 + 验证,并最终在完成后关闭 shell
  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 

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

【问题讨论】:

  • 您不能为一个进程调用两次communicate()。我已经更新了答案。
  • communicate('hostname\ntime\nexit\n') 可能吗?您真的需要以交互方式处理流程,还是只执行多个命令?后者更容易。

标签: python subprocess


【解决方案1】:

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 上,你可以考虑它。

【讨论】:

  • 我发现我错过了 stdin=PIPE。让我试一试
  • 是的,stdin=PIPE 是必不可少的。认为这是问题所在。
  • 那么我如何像上面那样运行两次通信调用呢?上面的程序挂了? (我的例子中的那个)
  • 好吧,我现在明白了。我可以创建一些基础设施来创建命令列表并调用 Process n 次以及一些断言基础设施。
【解决方案2】:

您可能会发现 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

【讨论】:

  • 据我了解,sh 和 pexpect 是 POSIX-only 库。
  • 我的意思是类 Unix 系统。 Windows在这里确实是一个问题。一切似乎都正常,但有很多令人讨厌的细节,比如 select() 不适用于管道。一周前,我在一个应该同时在 Linux 和 Windows 上运行的项目中面临几乎相同的任务,而我针对 Windows 的所有解决方案都很糟糕。
  • 啊,对不起@Ellioh。我只是在开玩笑……通常没有人愿意在 Windows 中进行命令行操作,因为 Windows 有自己的 API 来处理事情(想想 Microsoft PowerShell)。
  • 很棒的图书馆,正是我所期待的。
猜你喜欢
  • 2011-10-30
  • 2016-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-27
  • 2016-03-16
  • 1970-01-01
相关资源
最近更新 更多