子处理管道写入文件故障

时间:2013-03-14 05:26:18

标签: python shell unix subprocess pipe

在shell中执行此操作会获得切实的结果:

wget -O c1 --no-cache "http://some.website" | sed "1,259d" c1 | sed "4,2002d"

在Python中执行此操作无需任何操作:

subprocess.call(shlex.split("wget -O c1 --no-cache \"http://some.website/tofile\""))
c1 = open("c1",'w')
first = subprocess.Popen(shlex.split("sed \"1,259d\" c1"), stdout=subprocess.PIPE)

subprocess.Popen(shlex.split("sed \"4,2002d\""), stdin=first.stdout, stdout=c1)
c1.close()

这样做也没有结果:

c1.write(subprocess.Popen(shlex.split("sed \"4,2002d\""), stdin=first.stdout, stdout=subprocess.PIPE).communicate()[0])

通过'得到我什么都不'我的意思是文件中的空白输出。有没有人在这里看到任何与众不同的东西?

4 个答案:

答案 0 :(得分:3)

我总是使用plumbum来运行外部命令。它提供了一个非常直观的界面,当然,也为我提供了逃避。

看起来像:

from plumbum.cmd import wget, sed
cmd1 = wget['-O', 'c1']['--no-cache']["http://some.website"]
cmd2 = sed["1,259d"]['c1'] | sed["4,2002d"]
print cmd1
cmd1()  # run it
print cmd2
cmd2()  # run it

答案 1 :(得分:2)

语句c1 = open("c1",'w')打开文件c1进行写入并截断任何现有数据,因此写入文件的所有内容都会在调用sed之前被删除。

无论如何,我认为shlex.split通常很尴尬。我更喜欢手动构建args列表:

from subprocess import Popen, PIPE

p0 = Popen(['wget', '-O', '-', 'http://www.google.com'], stdout=PIPE)
p1 = Popen(['sed', '2,8d'], stdin=p0.stdout, stdout=PIPE) 
with open('c1', 'w') as c1:
    p2 = Popen(['sed', '2,7d'], stdin=p1.stdout, stdout=c1)
    p2.wait()

然而,没有明显的理由让Python程序员应该调用sed。 Python有字符串方法和正则表达式。另外,您可以使用urllib2.urlopen代替wget。

答案 2 :(得分:1)

为什么不直接在管道中执行所有操作并将输出发送到文件?

wget -O - "http://www.google.com" | sed "1,259d" | sed "4,2002d" > c1

或者,如果您不想将其发送到文件,而是希望它在stdout上:

wget -O - "http://www.google.com" | sed "1,259d" | sed "4,2002d"

如果你想用Python做到这一点:

pipe = subprocess.Popen(shlex.split("wget -O - \"http://www.google.com\" | sed \"1,259d\" | sed \"4,2002d\""), stdout=subprocess.PIPE)
result = pipe.communicate()[0]

答案 3 :(得分:0)

为了让那些或多或少可能遇到同一类型问题的人们的生活更轻松,我决定发布最终修订后的代码,该代码考虑了c1和覆盖的评论数据的。特别感兴趣的是communicate()的使用,这有助于完全消除僵尸过程的任何表现,这非常令人恼火。此外,我发现在不需要管道的部分使用subprocess.call很有用。最后不需要wait()。最终,远离sedwget是一个好主意,特别是使用Python的内置工具和urllib2

p0 = subprocess.call(shlex.split("wget -Oc1 --no-cache \"http://Some.website/tofile\""))
p1 = subprocess.Popen(shlex.split("sed \"1,261d\" c1"), stdout=subprocess.PIPE)

with open("cc1", 'w') as cc1:
    p2 = subprocess.Popen(shlex.split("sed \"3,2002d\""), stdin=p1.stdout, stdout=cc1)
    p2.communicate()
    p1.communicate()
    p3 = subprocess.call(shlex.split("mv cc1 c1"))