Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中创建一个空的Popen()对象?_Python_Popen_Subprocess - Fatal编程技术网

在Python中创建一个空的Popen()对象?

在Python中创建一个空的Popen()对象?,python,popen,subprocess,Python,Popen,Subprocess,有没有办法创建一个空的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当然

有没有办法创建一个空的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当然必须在第一次迭代开始时存在。我可以像以前一样通过simpy发出echo来解决这个问题,但我想知道是否有一种更简洁、更正确的方法?

在Unix上,使用
true
比使用
echo
稍微好一点
true
是一个不做任何事情并且总是成功的程序(请参见手册页中的笑声)。

如果您只想在运行时运行传递给您的函数的管道(=一个或多个|分隔的命令),无需费事:只需使用
subprocess.Pipe(pipeline,shell=true)
。它将自己处理管道。(“管道”是单个字符串,例如
“ls”
“ls/| wc”

如果出于某种原因,您真的希望将它们作为单独的管道启动,那么您的问题可以归结为:您有一个循环,但需要一个初始值来启动它。与其浪费打给波本的电话,我会这样做:

com = [["ls","/"],["wc"]]
p = None
for c in com:
    p = Popen(c, stdin=(p.stdout if p else None), stdout=PIPE, stderr=PIPE)
(顺便说一句,我放弃了我以前的回答,因为我误解了你在做什么。)

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

com[0] | com[1] | ... | com[n-1]
如果您不必担心“坏”字符和shell,最简单的方法就是将它们全部合并到一个大shell命令中:

p = subprocess.Popen(' | '.join(' '.join(words) for words in com), shell=True, ...)
或者,由于您最初希望stdout=None,因此可以使用@pst的技巧,简单地让p最初是.stdout为None的任何对象。但是您还应该注意,您依赖于系统来关闭循环中以前的每个子进程.Popen()s(以便它们的输出管道是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
如果在每个Popen()中重定向stderr=subprocess.STDOUT,这将通过管道将每个子命令的错误输出传输到下一个命令。要将它们全部管道化到程序中,您必须首先创建一个OS级管道对象,然后将每个对象连接到该(单个)管道的写入端,然后绕过子流程模块以获取指向它的“最终”子流程对象,以便其选择/轮询代码将从该管道中吸取任何数据。(由于subprocess.communicate()将只从两个这样的管道中读取多个,因此您无法单独捕获每个子命令的stderr输出。)


注:以上各项均未经测试…

Quack-Quack!在本例中,它不必是
Popen
对象;仅一个对象具有适当的
标准输出。。(不,从系统/操作系统的角度来看,[在大多数情况下]一个“空”的Popen没有什么意义:-)好吧,与仅仅创建一个伪Popen对象相比,创建一个带有stdout def的类似乎需要更多的工作。但我不确定什么是最正确的方法。我事先不知道该命令是什么,或者该命令中是否有管道。因此,在实际程序中,我的示例中的com变量是通过在任意“|”处拆分字符串创建的。这就是我不想使用循环的原因。对不起,我没有意识到你正在设置管道(你没有提到)。但是,如果您的实际程序将获得一个完整的管道并将其拆分,则无需麻烦:根本不拆分它,只需使用
subprocess.Popen(pipeline,shell=True)
(“管道”是您的程序现在拆分的地方)啊,对不起,我现在意识到我没有提到将命令进行管道化,我想这对我来说太明显了,以至于我没有意识到这一点都不明显非常感谢您的输入,看起来我需要对子流程进行一些阅读。嗯,我也学到了一些东西:-)。顺便问一下,您是否意识到,除了管道中的最后一个阶段,您的循环会丢弃所有的stderr?是的,我意识到这一点,并认为可能需要通过在迭代的每个步骤中将错误放在单独的列表中来解决,但使用
shell=True
也解决了这个问题。再次感谢你!:)谢谢,我不知道这是真的,但这似乎正是我所需要的。这将如何解决你的问题
true
,就像
echo
,将立即退出,并且将没有任何通信。哦,现在我看到了。。。我错过了你循环中的
stdin=p.stdout
。好把戏。我还没意识到你想把每个命令的日期传递到下一个命令。