Python: 使用subprocess模块无法读写其他命令行应用程序

1 投票
3 回答
1198 浏览
提问于 2025-04-15 13:04

我在Windows上使用Python 3.0,想要自动化测试一个命令行应用程序。用户可以在这个应用程序中输入命令,然后它会返回两个XML数据包的输出。一个是发送的数据包,另一个是接收的数据包。通过分析这些数据包,我可以验证结果。我的代码如下:

p = subprocess.Popen(SomeCmdAppl, stdout=subprocess.PIPE,

                   shell = True, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)

p.stdin.write((command + '\r\n').encode())
time.sleep(2.5)
testresult = p.stdout.readline()
testresult = testresult.decode()
print(testresult)

但是我没有得到任何输出。程序在我尝试使用readline()读取输出的地方卡住了。我试过read(),结果也是卡住。

当我手动运行这个命令行应用程序并输入命令时,我能正确地得到两个XML数据包的输出,如下所示:

Sent: <PivotNetMessage>
<MessageId>16f8addf-d366-4031-b3d3-5593efb9f7dd</MessageId>
<ConversationId>373323be-31dd-4858-a7f9-37d97e36eb36</ConversationId>
<SageId>4e1e7c04-4cea-49b2-8af1-64d0f348e621</SagaId>
<SourcePath>C:\Python30\PyNTEST</SourcePath>
<Command>echo</Command>
<Content>Hello</Content>
<Time>7/4/2009 11:16:41 PM</Time>
<ErrorCode>0</ErrorCode>
<ErrorInfo></ErrorInfo>
</PivotNetMessagSent>

Recv: <PivotNetMessage>
<MessageId>16f8addf-d366-4031-b3d3-5593efb9f7dd</MessageId>
<ConversationId>373323be-31dd-4858-a7f9-37d97e36eb36</ConversationId>
<SageId>4e1e7c04-4cea-49b2-8af1-64d0f348e621</SagaId>
<SourcePath>C:\PivotNet\Endpoints\Pipeline\Pipeline_2.0.0.202</SourcePath>
<Command>echo</Command>
<Content>Hello</Content>
<Time>7/4/2009 11:16:41 PM</Time>
<ErrorCode>0</ErrorCode>
<ErrorInfo></ErrorInfo>
</PivotNetMessage>

但是当我使用communicate()时,我只收到了发送的数据包,却没有收到接收的数据包。为什么我会缺少接收的数据包呢?communicate(0应该能从标准输出中获取所有内容,对吧?

p = subprocess.Popen(SomeCmdAppl, stdout=subprocess.PIPE,

                   shell = True, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
p.stdin.write((command + '\r\n').encode())
time.sleep(2.5)
result = p.communicate()[0]
print(result)

有没有人能给我一个可以工作的示例代码?我不知道是否需要在不同的线程中进行读写。请帮帮我。我需要进行重复的读写操作。Python中有没有什么高级模块可以使用?我觉得Pexpect模块在Windows上不太好用。

3 个回答

0

你有没有想过用pexpect来代替subprocess呢?pexpect可以处理一些细节问题,这些问题可能是导致你的代码无法正常工作的原因(比如缓冲区的刷新等)。虽然它可能还不支持Python 3,但在Python 2.x中运行得很好。

可以查看这里: http://pexpect.sourceforge.net/pexpect.html

0

试着用 communicate 来发送你的输入,而不是用 write

result = p.communicate((command + '\r\n').encode())[0]
1

这是一个很常见的问题,比如你可以看看:

(其实,你在提问的时候应该已经看到这些了...?!)

我有两个想法:

  • p.stdin.write((command + '\r\n').encode()) 这个操作也是缓冲的,所以你的子进程可能根本没有看到它的输入。你可以尝试刷新这个管道。
  • 在其他问题中,有人建议在子进程上使用stdout.read()而不是readline(),并且要读取适量的字符。你可以试着实验一下这个方法。

把你的结果发出来吧。

撰写回答