2012-03-08 75 views
1

有没有什么办法来创建一个空的Popen()对象,或者可能有其他方式来解决我想要做的事情。在Python中创建一个空的Popen()对象?

我给一个代码例子来说明什么,我试图完成:

com = [["ls","/"],["wc"]] 
p = Popen(["echo"]) 
for c in com: 
    p = Popen(c, stdin=p.stdout,stdout=PIPE,stderr=PIPE) 
l = list(p.communicate()) 

我有一个包含系统命令,我想运行一个嵌套列表,通过列表迭代,但为了这个工作,p必须在第一次迭代开始时存在。我可以像我一样解决这个问题,通过简单地发出一个回声,但我想知道是否有更整洁和更正确的方法?

+1

*嘎嘎庸医!*在这个例子中,它不*必须是'Popen'对象;只是一个对象有一个合适的'stdout' ..(不,从一个系统/操作系统的角度来看,一个“空”Popen没什么意义[在大多数情况下] :-) – 2012-03-08 08:55:08

+0

好吧,似乎更多的工作来创建一个类与仅创建虚拟Popen对象相比,它是一个stdout def。不知道什么是最正确的方式。 – 2012-03-08 10:23:30

回答

1

如果您只想运行在运行时传递给您的函数的管道(=一个或多个|分隔命令),则不需要去解决所有问题:只需使用subprocess.Pipe(pipeline, shell=True)即可。它将自行处理管道。 (“管道”是单个字符串,例如"ls""ls/| wc"

如果由于某种原因,您确实想将这些作为单独的管道启动,您的问题归结为:您有一个循环,但您需要一个初始值启动它。与其浪费到POPEN一个电话,我会做这样的:

com = [["ls","/"],["wc"]] 
p = None 
for c in com: 
    p = Popen(c, stdin=(p.stdout if p else None), stdout=PIPE, stderr=PIPE) 

(PS。我抛弃我的旧的答案,因为我误解了你在做什么)。

+0

我不知道命令会是什么,或者命令中是否有任何管道。所以在真正的程序中,我的示例中的com变量是通过在任何'|'处分割字符串来创建的。这就是我不想循环的原因。 – 2012-03-08 10:31:26

+0

对不起,我没有意识到你正在建立一个管道(你没有提到它)。但是,如果你真正的程序会给出一个完整的管道,将其分解了,没有必要去到这一切的烦恼:完全不拆,只需要使用'subprocess.Popen(管道,壳=真)'(“管道“是你的程序现在在拆分|) – alexis 2012-03-08 11:37:44

+0

啊哈,对不起,我现在意识到,我没有提及pipeing命令一起什么,我想它是如此明显,我认为我并没有意识到,这是不一点都不明显。 :)非常感谢您的输入,它看起来像我需要做一些读取子进程。 – 2012-03-08 14:04:47

1

在Unix上,使用true而不是echo可能会稍微好一些。 true是一个什么都不做并且总是成功的程序(参见手册页中的笑)。

+0

谢谢,我不知道真的,但它似乎正是我需要的。 – 2012-03-08 10:34:43

+0

这是怎么解决你的问题?像'echo'一样,'true'将立即退出,并且没有任何可沟通的东西。 – alexis 2012-03-08 11:26:12

+0

哦,现在我看到它...我已经错过在循环的'标准输入= p.stdout'。好戏。我没有意识到你想要从每个命令到下一个命令的日期。 – alexis 2012-03-08 11:32:50

1

你想要的这里是(显然)系列管道:

com[0] | com[1] | ... | com[n-1] 

最简单的方法,如果你不担心“坏”字和炮弹,是刚刚加入他们所有成一个大的shell命令:

p = subprocess.Popen(' | '.join(' '.join(words) for words in com), shell=True, ...) 

另外,既然你想标准输出=无最初,你可以用@简单地具有p的PST的惯用伎俩最初与无的.stdout任何对象。但是你也应该注意到你依赖于系统来关闭你之前的每个子进程.Popen()(因此它们的输出管道在循环内部是close()d),这与CPython一起发生,但不与Jython一起发生(据我了解 - 我没有实际使用过Jython)。所以,你可能需要一个更明确的循环:

# assumes len(com) >= 1 
p0 = subprocess.Popen(com[0], stdout=subprocess.PIPE) 
# don't use stderr=subprocess.PIPE -- if you want stderr to be piped too 
# use stderr=subprocess.STDOUT, or create a stderr pipe early manually and 
# supply the fd directly; see hints in text below. 
for words in com[1:]: 
    p1 = subprocess.Popen(words, stdin=p0.stdout, stdout=subprocess.PIPE) 
    # again you don't want to set stderr to subprocess.PIPE here 
    p0.stdout.close() # now that it's going to p1, we must ditch ours 
    p0 = p1 # p1 becomes the input to any new p1 we create next time 
# at this point, use p0.communicate() to read output 

如果您重定向标准错误= subprocess.STDOUT每个POPEN(),这将管道从每个子命令输出的错误到下一个。要将它们全部传送到您的程序中,您必须首先创建一个OS级别的管道对象,然后将每个管道连接到该(单个)管道的写入端,然后绕过子进程模块以获取指向它的“最终”子进程对象,因此它的选择/轮询代码将从该管道中吸取任何数据。 (由于subprocess.communicate()将只读多从两个这样的管道,你不能独立捕获每个单独的子命令的stderr输出。)

注:以上都不是测试...