感谢以下有用的建议:
所以当我
时似乎已经修复了新代码:
import subprocess
import shlex
import logging
def run_shell_commands(cmds):
""" Run commands and return output from last call to subprocess.Popen.
For usage see the test below.
"""
# split the commands
cmds = cmds.split("|")
cmds = list(map(shlex.split,cmds))
logging.info('%s' % (cmds,))
# run the commands
stdout_old = None
stderr_old = None
p = []
for cmd in cmds:
logging.info('%s' % (cmd,))
p.append(subprocess.Popen(cmd,stdin=stdout_old,stdout=subprocess.PIPE,stderr=subprocess.PIPE))
stdout_old = p[-1].stdout
stderr_old = p[-1].stderr
return p[-1]
pattern = '"^85567 "'
file = "j"
cmd1 = 'grep %s %s | sort -g -k3 | head -10 | cut -d" " -f2,3' % (pattern, file)
p = run_shell_commands(cmd1)
out = p.communicate()
print(out)
原帖:
我花了很长时间试图解决一个简单的子进程问题.Popen。
代码:
import subprocess
cmd = 'cat file | sort -g -k3 | head -20 | cut -f2,3' % (pattern,file)
p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
for line in p.stdout:
print(line.decode().strip())
文件输出~1000行的长度:
...
sort: write failed: standard output: Broken pipe
sort: write error
文件输出>长度为241行:
...
sort: fflush failed: standard output: Broken pipe
sort: write error
文件输出< 241行的长度很好。
我一直在阅读文档和谷歌搜索疯狂,但有一些基本的东西模块,我缺少...可能与缓冲区。我尝试过p.stdout.flush()并使用缓冲区大小和p.wait()。我试图用'睡眠20;等命令重现这一点; cat moderatefile'但这似乎运行没有错误。
答案 0 :(得分:12)
来自subprocess文档的食谱:
# To replace shell pipeline like output=`dmesg | grep hda`
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]
答案 1 :(得分:5)
这是因为你不应该在传递给subprocess.Popen
的命令中使用“shell管道”,你应该像这样使用subprocess.PIPE
:
from subprocess import Popen, PIPE
p1 = Popen('cat file', stdout=PIPE)
p2 = Popen('sort -g -k 3', stdin=p1.stdout, stdout=PIPE)
p3 = Popen('head -20', stdin=p2.stdout, stdout=PIPE)
p4 = Popen('cut -f2,3', stdin=p3.stdout)
final_output = p4.stdout.read()
但是我必须说你想要做的事情可以用纯python完成,而不是调用一堆shell命令。
答案 2 :(得分:1)
我一直有同样的错误。甚至把管道放在一个bash脚本中并执行它而不是Python中的管道。从Python中它会得到破坏的管道错误,从bash它不会。
在我看来,也许在头部之前的最后一个命令抛出一个错误,因为它的(排序)STDOUT被关闭了。 Python必须接受这一点,而对于shell,错误是沉默的。我已经改变了我的代码以消耗整个输入,错误就消失了。
使用较小的文件也很有意义,因为管道可能会在磁头退出之前缓冲整个输出。这可以解释较大文件的中断。
例如,而不是头部-1' (在我的情况下,我只想要第一行),我做了一个awk' NR == 1'根据' head -X'发生在管道中。
答案 3 :(得分:0)
您不需要shell=True
。不要调用shell。我就是这样做的:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
stdout_value = p.communicate()[0]
stdout_value # the output
使用此功能后,查看是否遇到缓冲区问题?
答案 4 :(得分:0)
尝试使用communicate(),而不是直接从stdout读取。
python docs说:
“警告使用communication()而不是 .stdin.write,.stdout.read或 .stderr.read以避免由于的死锁 任何其他OS管道缓冲区 填补和阻止孩子 过程“。
http://docs.python.org/library/subprocess.html#subprocess.Popen.stdout
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
output = p.communicate[0]
for line in output:
# do stuff