有没有办法创建一个空的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当然必须存在于第一次迭代的开始。我可以通过简单的发出回声来解决这个问题,但是我想知道是否有更整洁,更正确的方式?
答案 0 :(得分:1)
在Unix上,使用true
而不是echo
可能略胜一筹。 true
是一个什么都不做并且总是成功的程序(请参阅手册页中的笑声)。
答案 1 :(得分:1)
如果你想要的只是运行一个在运行时传递给你的函数的管道(=一个或多个| -separated命令),不需要遇到所有麻烦:只需使用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。因为我误解了你在做什么,所以我放弃了我的旧答案。)
答案 2 :(得分:1)
你想要的是(显然)一系列的管道:
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的任何对象。但是你还应该注意,你依赖于系统来关闭你以前的每个subprocess.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级别的管道对象,然后将每个管道对象连接到该(单个)管道的写入端,然后潜入子进程模块以获取指向它的“最终”子进程对象,这样它的select / poll代码就会从该管道中吸取任何数据。 (由于subprocess.communicate()只能从两个这样的管道读取多个数据,因此无法独立捕获每个子命令的stderr输出。)
注意:以上都没有经过测试......