我是python的新手,多年来一直使用perl。我一直做的典型事情是perl打开一个命令作为管道并将其输出分配给局部变量进行处理。换句话说:
"open CMD, "$command|";
$output=<CMD>;
一块蛋糕。我想我可以用python这样做类似的东西:
args=[command, args...]
process=subprocess.Popen(args, stdout=subprocess.PIPE)
output=process.communicate()
到目前为止一切顺利。现在提出一个大问题......
如果我在多个平台上使用ssh启动该命令,那么我可以在select循环中监视perl中的描述符,以便在结果进入时处理结果。我确实找到了python select和poll模块但是我并不完全确定如何使用它们。文档说poll将采用文件句柄,但是当我尝试将上面的变量'process'传递给poll.register()时,我得到一个错误,它必须是int或者有一个fileno()方法。由于Popen()使用了stdout,我试着调用
poll.register(process.stdout)
它不再抛出错误,而只是挂起。
有关如何制作此类作品的任何建议/指示?
答案 0 :(得分:7)
使用select.poll
:您需要pass objects with a fileno
method or real file descriptors (integers):
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))
你会看到它每两秒钟暂停一次,然后在可用时产生更多输出。 “技巧”是p1.stdout
是一个普通的文件类对象,其fileno
方法返回文件描述符号。这就是select
所需要的一切。
请注意,我使用stdout
从os.read
开始阅读,而不是简单地调用stdout.read
。这是因为像stdout.read(1024)
这样的调用会使程序等到读取所请求的字节数。只有在达到EOF时才会返回更少的字节,但由于永远不会达到EOF,stdout.read
调用将阻塞,直到至少读取了1024个字节为止。
这与os.read
函数不同,os.read(stdout.fileno(), 1024)
函数在没有可用字节的情况下没有任何关于提前返回的问题 - 它会立即返回可用的内容。换句话说,从stdout
返回少于1024个字节并不表示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))
才能读取:
select.POLLHUP
关闭的FD由返回的unregister
事件发出信号。然后,您可以调用{{1}}方法,最后在所有FD关闭时退出循环。
最后,请注意,您当然可以创建一个字典,其中包含从文件描述符到类文件对象的映射,从而返回到您启动的进程。
答案 1 :(得分:2)
import subprocess
p = subprocess.Popen('apt-get autoclean', stdout=subprocess.PIPE, stderr = None, shell=True)
for line in iter(p.stdout.readline, ''):
print line
p.stdout.flush()
p.stdout.close()
print ("Done")