在Python中一次读取stdin行

时间:2017-08-30 23:29:57

标签: python python-3.x

我试图通过发送一系列命令并捕获输出来测试特定的聊天程序。

我如何通过:

sleep 2
echo test
sleep 2
echo test1

我试过这个:

(sleep 2; echo test; sleep 2; echo test1) | python3 test.py

但它只打印第一部分,而第二部分我什么都没得到。它反而进入了无限循环。

python程序的代码是:

import sys, select

while True:
  socket_list = [sys.stdin]
  read_sockets, write_sockets, error_sockets = select.select(socket_list, [], [])
  for sock in read_sockets:
    message = sys.stdin.readline()
    sys.stdout.write("> %s: ")
    sys.stdout.flush()

我应该提到这不是完整的程序,但它是帮助重新创建完全相同效果的部分。

2 个答案:

答案 0 :(得分:3)

您的示例进入循环,因为echo test1 stdin 关闭后read()始终返回空。 此外,您不应该使用select进行其他阻止通话。如果你能 在多个对象上使用它,您仍然可以被readline阻止 来自上一次活动。

stdin 读取一行时,您不需要使用 select.select()。可能是实现这一目标的最简单方法:

for line in sys.stdin:
    print(line)

如果要使用stdin或文件列表作为参数 你的程序,Python fileinput模块 是开箱即用的解决方案。

如果你想/需要使用select.select()

import os, sys, select

buffer = ""
while True:
  select.select([sys.stdin.fileno()], [], [])
  read = os.read(sys.stdin.fileno(), 512)

  # empty read: EOF
  if len(read) == 0:
    # buffer might not be empty
    if len(buffer) > 0:
      sys.stdout.write(buffer + "\n")

    break

  # find newlines
  parts = read.split("\n")
  buffer += parts.pop(0)

  while len(parts) > 0:
    sys.stdout.write(buffer + "\n")
    buffer = parts.pop(0)

物体准备好后, select.select 疏导。在这种情况下唯一的对象是 stdin 。不止一个 对象,您需要检查select.select的返回值以查找 哪一个准备好了。 os.read()用于执行非阻塞读取 stdin (或者: 它可以使用stdin.read(1)一次读取一个字符)。 read.split("\n")用于查找换行符,请注意它 可能一次读取会产生多行。

答案 1 :(得分:1)

strace上运行cat之后,我创建了这个:

import sys

while True:
    data = sys.stdin.read()
    if not len(data):
        break
    sys.stdout.write(data)

<强>命令

(sleep 2; echo test; sleep 2; echo test1) | python3 test.py

<强>输出

test
test1

这个解决方案依赖于这个事实:

  

如果已到达文件末尾,f.read()将返回一个空字符串('')。

请参阅Methods of File Objects

如果您需要使用select的版本:

import os
import select
import sys

while True:
    rlist = [sys.stdin.fileno()]
    wlist = []
    xlist = []
    rlist, wlist, xlist = select.select(rlist, wlist, xlist)
    if sys.stdin.fileno() in rlist:
        data = os.read(sys.stdin.fileno(), 4096)
        if not len(data):
            break
        sys.stdout.write(data)