首页 文章

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

提问于
浏览
13

感谢以下有用的建议:

所以我似乎已经修好了

  • 单独命令到Popen的单独调用

  • stderr = subprocess.PIPE作为每个Popen链的参数 .

新代码:

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

    subprocess docs上的食谱:

    # 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]
    
  • 0

    这是因为你不应该在传递给 subprocess.Popen 的命令中使用"shell pipes",你应该像这样使用 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命令 .

  • 5

    我一直有同样的错误 . 甚至把管道放在一个bash脚本中并执行它而不是Python中的管道 . 从Python它将得到破坏的管道错误,从bash它不会 .

    在我看来,也许在头部之前的最后一个命令抛出错误,因为它的(排序)STDOUT被关闭 . Python必须接受这一点,而对于shell,错误是沉默的 . 我已经改变了我的代码以消耗整个输入并且错误消失了 .

    因为管道可能会在磁头退出之前缓冲整个输出,因此使用较小的文件也是有意义的 . 这可以解释较大文件的中断 .

    例如,而不是'头-1'(在我的情况下,我只想要第一行),我做了一个awk'NR == 1'

    根据管道中出现'head -X'的位置,可能有更好的方法 .

  • 1

    你不需要 shell=True . 不要调用shell . 我就是这样做的:

    p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    stdout_value = p.communicate()[0] 
    stdout_value   # the output
    

    使用它后看看你是否遇到缓冲区的问题?

  • 12

    尝试使用communicate(),而不是直接从stdout读取 .

    python文档说这个:

    “警告使用communic()而不是.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
    

相关问题