新手python子进程:“写入错误:断管”

时间:2010-11-05 14:03:05

标签: python subprocess popen

感谢以下有用的建议:

所以当我

时似乎已经修复了
  1. 将命令分离为对Popen的单独调用
  2. stderr = subprocess.PIPE作为每个Popen链的参数。
  3. 新代码:

    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'但这似乎运行没有错误。

5 个答案:

答案 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