【问题标题】:Eagerly return lines from stdin Python急切地从标准输入 Python 返回行
【发布时间】:2015-12-18 15:20:47
【问题描述】:

我正在制作一个脚本,其中包含一些其他脚本输出。另一个脚本需要一段时间才能完成,并将进度连同我要解析的数据一起打印到控制台上。

由于我将结果传送到我的脚本,我希望能够做两件事。当我的输入出现时,我想将它回显到屏幕上。命令完成后,我想要一个通过标准输入的行列表。

我的第一个想法是使用一个简单的

for line in sys.stdin:
     sys.stdout.write(line + '\n')
     lines.append(line)
     sys.stdout.flush()

但令我惊讶的是,该命令一直等到标准输入到达 EOF,直到它开始产生行。

我目前的解决方法是这样的:

line = sys.stdin.readline()
lines = []
while line:
    sys.stdout.write(line.strip() + '\n')
    lines.append(line.strip())
    sys.stdout.flush()
    line = sys.stdin.readline()

但这并不总是等到整个输入被使用。

还有其他方法可以做到这一点吗? for 解决方案的行为方式似乎很奇怪。

【问题讨论】:

  • 我用 | 管道。 Mac OSX
  • 你能澄清你的意思吗?“......这并不总是等到整个输入被使用。”您的解决方法脚本对我来说很好。

标签: python stdin


【解决方案1】:

已编辑以回答您关于在输入结束时退出的问题

您描述的解决方法,或类似下面的类似方法似乎是必要的:

#!/usr/bin/env python

import sys

lines = []

while True:
    line = sys.stdin.readline()
    if not line:
        break
    line = line.rstrip()
    sys.stdout.write(line + '\n')
    lines.append(line)
    sys.stdout.flush()

这在 python 手册页中的-u 选项下进行了解释:

   -u     Force stdin, stdout and stderr to  be  totally  unbuffered.   On
          systems  where  it matters, also put stdin, stdout and stderr in
          binary mode.  Note that there is internal  buffering  in  xread-
          lines(),  readlines()  and  file-object  iterators ("for line in
          sys.stdin") which is not influenced by  this  option.   To  work
          around  this, you will want to use "sys.stdin.readline()" inside
          a "while 1:" loop.

我创建了一个包含上述代码的文件 dummy.py,然后运行:

for i in 1 2 3 4 5; do sleep 5; echo $i; echo; done | ./dummy.py

这是输出:

harold_mac:~ harold$ for i in 1 2 3 4 5; do sleep 5; echo $i; done | ./dummy.py
1

2

3

4

5

harold_mac:~ harold$

【讨论】:

  • 如何知道输入何时完成?行会包含 EOF 标记吗?
  • 我会使用sys.stdin.closed 来寻找EOF
  • 如果管道中的第一个脚本输出空行,则编辑后的答案将不起作用。 if not line 检查应该在 line = line.rstrip() 之前。
  • @Aya 谢谢你,你是对的。我已经用空行验证它只在最后停止。
【解决方案2】:

Python 使用缓冲输入。如果您与python --help 核对,您会看到:

-u     : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x

所以尝试使用无缓冲选项:

command | python -u your_script.py

【讨论】:

  • 我会用这个,但是当我的命令通过调用shebang解释器被调用时,有没有办法传递这个参数?
  • @BartlomiejLewandowski:当然,我一直这样做。 Here 你可以找到三种不同的方法来实现这一点。我一般用#!/usr/bin/python -u的方式,不过你可以选择适合自己的。
  • 就像这样 #!/usr/bin/python -u ,请注意,这种方式只能识别 1.st 参数
【解决方案3】:

其他人已经告诉过您有关无缓冲输出的信息。我将添加一些想法:

  1. 通常最好将调试信息打印到 stderr,stderr 输出通常是无缓冲的
  2. 将中间输出委托给特殊工具更简单。例如,有一个tee 实用程序,它允许拆分先前命令的标准输出。假设您在 bash,您可以立即将中间输出打印到 stdout,并使用 process substitution 而不是打印到文件(而不是 awk,您将调用您的 python 脚本):

    $ python -c 'for i in range(5): print i+1' | tee >( awk '{print "from awk", $0**2 }')
    1
    2
    3
    4
    5
    from awk 1
    from awk 4
    from awk 9
    from awk 16
    from awk 25
    

【讨论】:

    【解决方案4】:

    您需要在您的 python 程序中创建 1) 标准输入和 2) 管道另一侧的标准输出以进行行缓冲。得到这个 1)在你的程序中使用stdin = os.fdopen(sys.stdin.fileno(), 'r', 1); 2)使用stdbuf -oL改变其他程序输出的缓冲模式:

    stdbuf -oL otherprogram | python yourscript.py
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-16
      • 2015-07-05
      • 2018-07-11
      • 1970-01-01
      • 2011-10-21
      • 1970-01-01
      相关资源
      最近更新 更多