【问题标题】:can not read correctly from STDIN无法从 STDIN 正确读取
【发布时间】:2012-03-15 08:13:48
【问题描述】:

我在 python 脚本中从 STDIN 读取时遇到了一个奇怪的问题。

这是我的用例。我已经为 rsyslog 配置了一个输出模块,因此 rsyslog 可以将日志消息通过管道传输到我的 Python 脚本。

我的 Python 脚本真的很简单:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys

fd = open('/tmp/testrsyslogomoutput.txt', 'a')
fd.write("Receiving log message : \n%s\n" % ('-'.join(sys.stdin.readlines())))
fd.close()

如果我运行echo "foo" | mypythonscript.py,我可以在目标文件/tmp/testrsyslogomoutput.txt 中获得“foo”。但是,当我在 rsyslog 中运行它时,似乎只有在我停止/重新启动 rsyslog 时才会发送消息(我相信某些缓冲区会在某个时候被刷新)。

我首先认为这是 Rsyslog 的问题。所以我用一个 shell 替换了我的 python 程序,没有改变任何 rsyslog 配置。 shell 脚本与 rsyslog 完美配合,正如您在下面的代码中看到的那样,该脚本非常简单:

#! /bin/sh
cat /dev/stdin >> /tmp/testrsyslogomoutput.txt

由于我的 shell 脚本可以工作,但我的 Python 脚本不能,我相信我在 Python 代码的某个地方犯了一个错误,但我找不到在哪里。如果你能指出我的错误,那就太好了。

提前致谢:)

【问题讨论】:

    标签: python rsyslog


    【解决方案1】:

    readlines 在完成文件读取之前不会返回。由于输入标准输入的管道永远不会完成,readlines 也永远不会完成。停止 rsyslog 会关闭管道并让它完成。

    【讨论】:

      【解决方案2】:

      如果你改用readline(),它将返回\n,尽管这只会写一行然后退出。

      如果你想继续写行,只要它们在那里,你可以使用一个简单的for

      for line in fd:
        fd.write("Receiving log message : \n%s\n" % (line)
      fd.close()
      

      【讨论】:

      • 我试过这个。问题仍然相同。我试图遍历 sys.stdin 和 /dev/stdin 并且输入仅在发送 \n 时写入。如上所述使用 readline 的替代方法也不起作用。
      【解决方案3】:

      我还怀疑原因是 rsyslog 没有终止。 readlines() 在到达真正的 EOF 之前不应返回。但是为什么 shell 脚本会有不同的行为呢?也许使用 /dev/stdin 是原因。试试这个版本,看看它是否还能在不挂起的情况下运行:

      #!/bin/sh
      cat >> /tmp/testrsyslogomoutput.txt
      

      如果这有所作为,您还将有一个修复:打开并从 python 读取 /dev/stdin,而不是 sys.stdin。

      编辑:所以cat 以某种方式读取 stdin 处等待的任何内容并返回,但 python 阻塞并等待直到 stdin 用尽。奇怪的。您也可以尝试将readlines() 替换为单个read(),然后是split("\n"),但在这一点上,我怀疑这会有所帮助。

      所以,忘记诊断,让我们尝试一种解决方法:强制标准输入执行非阻塞 i/o。以下应该做到这一点:

      import fcntl, os
      
      # Add O_NONBLOCK to the stdin descriptor flags 
      flags = fcntl.fcntl(0, fcntl.F_GETFL)
      fcntl.fcntl(0, fcntl.F_SETFL, fl | os.O_NONBLOCK)
      
      message = sys.stdin.read().split("\n")  # Read what's waiting, in one go
      fd = open('/tmp/testrsyslogomoutput.txt', 'a')
      fd.write("Receiving log message : \n%s\n" % ('-'.join(message)))
      fd.close()
      

      您可能希望将其与python -u 结合使用。希望它有效!

      【讨论】:

      • 我尝试了您提出的建议,但没有任何区别。它仍然可以完美地与这个简单的 shell 脚本配合使用。我还尝试在我的 python 脚本中读取 /dev/stdin(没有 readlines()),但它仍然挂起。
      • 哦,好吧。下一个想法:通过使用 -u 标志调用 python,将 python 的 i/o 缓冲排除在等式之外。
      • 感谢 Alexis 的支持,我也尝试了 python -u 并没有改变任何东西。
      • 似乎@abalus 遇到了与 Apache 相同的问题:stackoverflow.com/questions/7056306/…
      • 我认为@abalus 有相反的问题:在他的设置中,读取会立即返回而不会阻塞,但是当 cat 以某种方式返回而不会阻塞时,您的程序会阻塞。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      • 2017-01-02
      • 1970-01-01
      • 1970-01-01
      • 2012-08-11
      • 1970-01-01
      相关资源
      最近更新 更多