【问题标题】:Read from stdin AND forward it to a subprocess in Python从标准输入读取并将其转发到 Python 中的子进程
【发布时间】:2017-04-17 12:59:29
【问题描述】:

我正在为一个可选择接受来自 STDIN 的输入的程序编写一个包装脚本。我的脚本需要处理文件的每一行,但它还需要将 STDIN 转发到它正在包装的程序。在极简形式中,它看起来像这样:

import subprocess
import sys

for line in sys.stdin:
    # Do something with each line
    pass

subprocess.call(['cat'])

请注意,我实际上并不是要包装 cat,它只是作为示例来演示 STDIN 是否被正确转发。

在上面的例子中,如果我注释掉for循环,它就可以正常工作。但是,如果我使用 for 循环运行它,则不会转发任何内容,因为我已经读到了 STDIN 的末尾。我不能 seek(0) 到文件的开头,因为你不能在流上搜索。

一种可能的解决方案是将整个文件读入内存:

import subprocess
import sys

lines = sys.stdin.readlines()
for line in lines:
    # Do something with each line
    pass

p = subprocess.Popen(['cat'], stdin=subprocess.PIPE)
p.communicate(''.join(lines))

有效,但内存效率不高。谁能想到更好的解决方案?也许是一种拆分或复制流的方法?

其他约束:

  1. 子进程只能调用一次。所以我不能一次读取一行,处理它,然后转发给子进程。
  2. 该解决方案必须在 Python 2.6 中运行

【问题讨论】:

  • 如果我理解正确的话,你想基本上将数据从stdin 转发到子进程的stdin
  • 是的,但如果我只想将stdin 转发到子进程,那么我只需要subprocess.call(['cat'])。我想转发stdin 并且能够阅读和处理它。
  • 很难判断我是否正确理解了您的问题。从:python -c $'import subprocess;\nimport sys;\np = subprocess.Popen(["cat", "-n"], stdin=subprocess.PIPE);\nfor line in iter(sys.stdin.readline,""): p.stdin.write(line)' 开始(把它放在一个普通的 .py 文件中,我只是把它放在一行上,这样我就可以在这个评论中得到它)。然后在p.stdin.write(line) 之前插入do_something_else_with(line)。由于某种原因,您的约束 #1 听起来对您不起作用,但我不明白为什么不这样做。你能澄清一下吗?

标签: python stream subprocess stdin


【解决方案1】:

这对你有用吗?

#!/usr/bin/env python2
import subprocess
import sys

p = subprocess.Popen(['cat'], stdin = subprocess.PIPE)

line = sys.stdin.readline()

####################
# Insert work here #
####################

line = line.upper()

####################

p.communicate(line)

例子:

$ echo "hello world" | ./wrapper.py 
HELLO WORLD

【讨论】:

  • 这个方案有两个问题: 1.它只转发stdin的第一行,而不是每一行。您需要使用readlines(复数)并在与子进程通信时加入它们。 2. 这与我已经提出的解决方案相同,但有点混乱。它具有将整个文件读入内存的缺陷。我正在寻找一种内存效率更高的解决方案(如果存在的话)。
  • 在这里大声思考。如果子进程之后的代码在一个 while 循环中连续读取一行,处理它然后进行通信怎么办?这不是类似于您正在寻找的类似流式传输的方法吗?
  • 查看附加约束:#1。
  • 是的,子进程会被调用一次,但是当脚本获取它们时,你会向它流式传输这些行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多