如何读取stdin?一些代码高尔夫挑战需要使用stdin进行输入。


当前回答

以下是学习Python的内容:

import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."

在Unix上,您可以通过以下方式进行测试:

% cat countlines.py | python countlines.py 
Counted 3 lines.

在Windows或DOS上,您可以执行以下操作:

C:\> type countlines.py | python countlines.py 
Counted 3 lines.

其他回答

其他人提出的答案:

for line in sys.stdin:
  print line

是非常简单和Python化的,但必须注意的是,脚本将等待EOF,然后开始迭代输入行。

这意味着tail-f error_log | myscript.py不会按预期处理行。

这种用例的正确脚本是:

while 1:
    try:
        line = sys.stdin.readline()
    except KeyboardInterrupt:
        break

    if not line:
        break

    print line

更新从评论中可以看出,在python2上可能只涉及缓冲区,因此在发出打印调用之前,您最终会等待缓冲区填充或EOF。

我在读取通过管道连接到它的套接字时遇到了一些问题。当套接字关闭时,它开始在活动循环中返回空字符串。所以这是我的解决方案(我只在linux中测试过,但希望它能在所有其他系统中运行)

import sys, os
sep=os.linesep

while sep == os.linesep:
    data = sys.stdin.readline()               
    sep = data[-len(os.linesep):]
    print '> "%s"' % data.strip()

因此,如果您开始监听套接字,它将正常工作(例如在bash中):

while :; do nc -l 12345 | python test.py ; done

您可以使用telnet调用它,也可以将浏览器指向localhost:1245

从sys.stdin读取,但要在Windows上读取二进制数据,您需要格外小心,因为sys.stdn是以文本模式打开的,它会损坏\r\n将其替换为\n。

解决方案是,如果检测到Windows+Python2,则将模式设置为二进制,在Python3上使用sys.stdin.buffer。

import sys

PY3K = sys.version_info >= (3, 0)

if PY3K:
    source = sys.stdin.buffer
else:
    # Python 2 on Windows opens sys.stdin in text mode, and
    # binary data that read from it becomes corrupted on \r\n
    if sys.platform == "win32":
        # set sys.stdin to binary mode
        import os, msvcrt
        msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
    source = sys.stdin

b = source.read()
import sys

for line in sys.stdin:
    print(line)

请注意,这将在末尾包含一个换行符。要删除末尾的换行符,请使用@brittohaloran所说的line.rstrip()。

非阻塞、字节模式、stdin->stdout:

# pipe.py

import os, sys, time

os.set_blocking(0, False)
sys.stdin = os.fdopen(0, 'rb', 0)
sys.stdout = os.fdopen(1, 'wb', 0)

while 1:
    time.sleep(.1)
    try: out = sys.stdin.read()
    except:
        sys.stdout.write(b"E")
        continue
    if out is None:
        sys.stdout.write(b"N")
        continue
    if not out:
        sys.stdout.write(b"_")
        break
    # working..
    out = b"<" + out + b">"
    sys.stdout.write(out)

sys.stdout.write(b".\n")

用法:

$ for i in 1 2 3; do sleep 1; printf "===$i==="; done | python3 pipe.py
NNNNNNNNN<===1===>NNNNNNNNN<===2===>NNNNNNNNN<===3===>_.

最小代码:

import os, sys

os.set_blocking(0, False)
fd0 = os.fdopen(0, 'rb', 0)
fd1 = os.fdopen(1, 'wb', 0)

while 1:
    bl = fd0.read()
    if bl is None: continue
    if not bl: break
    fd1.write(bl)

在Linux、Python 3.9.2上测试