我是python的新手,多年来一直使用perl.我一直做的典型事情是perl打开一个命令作为管道并将其输出分配给局部变量进行处理.换一种说法:
"open CMD, "$command|";
$output=<CMD>;
Run Code Online (Sandbox Code Playgroud)
一块蛋糕.我想我可以这样在python中做类似的事情:
args=[command, args...]
process=subprocess.Popen(args, stdout=subprocess.PIPE)
output=process.communicate()
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在提出一个大问题......
如果我在多个平台上使用ssh启动该命令,我可以在select循环中监视perl中的描述符,以便在它们进入时处理结果.我确实找到了python select和poll模块,但我不太确定如何使用它们.文档说poll将采用文件句柄,但是当我尝试将上面的变量'process'传递给poll.register()时,我得到一个错误,它必须是int或者有一个fileno()方法.由于Popen()使用了stdout,我试着调用
poll.register(process.stdout)
Run Code Online (Sandbox Code Playgroud)
它不再抛出错误,而只是挂起.
有关如何制作此类作品的任何建议/指示?
使用select.poll:您需要使用fileno方法或实际文件描述符(整数)传递对象:
import os, sys, select, subprocess
args = ['sh', '-c', 'while true; do date; sleep 2; done']
p1 = subprocess.Popen(args, stdout=subprocess.PIPE)
p2 = subprocess.Popen(args, stdout=subprocess.PIPE)
while True:
rlist, wlist, xlist = select.select([p1.stdout, p2.stdout], [], [])
for stdout in rlist:
sys.stdout.write(os.read(stdout.fileno(), 1024))
Run Code Online (Sandbox Code Playgroud)
您将看到它每两秒暂停一次,然后在可用时生成更多输出."技巧"是p1.stdout一个普通的类文件对象,其fileno方法返回文件描述符号.这就是所需要的一切select.
请注意,我正在stdout使用os.read而不是简单地调用stdout.read.这是因为类似的调用stdout.read(1024)会使程序等到读取所请求的字节数.只有在达到EOF时才会返回更少的字节,但由于永远不会达到EOF,因此stdout.read调用将被阻塞,直到读取至少1024个字节为止.
这与os.read函数不同,当没有更少的字节可用时,它没有任何关于提前返回的问题 - 它会立即返回可用的内容.换句话说,从后面获取少于1024个字节os.read(stdout.fileno(), 1024)不是stdout已关闭的符号.
使用select.epoll几乎相同,只是你得到一个你需要os.read能够读取的"原始"文件描述符(FD):
import os, sys, select, subprocess
args = ['sh', '-c', 'while true; do date; sleep 2; done']
p1 = subprocess.Popen(args, stdout=subprocess.PIPE)
p2 = subprocess.Popen(args, stdout=subprocess.PIPE)
poll = select.poll()
poll.register(p1.stdout)
poll.register(p2.stdout)
while True:
rlist = poll.poll()
for fd, event in rlist:
sys.stdout.write(os.read(fd, 1024))
Run Code Online (Sandbox Code Playgroud)
通过select.POLLHUP返回的事件发信号通知关闭的FD .然后,您可以调用该unregister方法,最后在关闭所有FD时退出循环.
最后,请注意,您当然可以创建一个字典,其中包含从文件描述符到类文件对象的映射,从而返回到您启动的进程.