如何读取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.

有几种方法可以做到这一点。

sys.stdin是一个类似于文件的对象,如果您想读取所有内容,或者想读取所有信息并通过换行自动拆分,则可以调用read或readlines函数。(您需要导入sys才能正常工作。)如果要提示用户输入,可以在Python2.X中使用raw_input,而在Python3中只需输入。如果您实际上只想读取命令行选项,可以通过sys.argv列表访问它们。

您可能会发现这篇关于Python中I/O的Wikibook文章也是一个有用的参考。


使用文件输入模块:

import fileinput

for line in fileinput.input():
    pass

fileinput将循环通过输入中指定为命令行参数中给定的文件名的所有行,如果没有提供参数,则循环通过标准输入。

注意:行将包含尾随换行符;要删除它,请使用line.rstrip()。


import sys

for line in sys.stdin:
    print(line)

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


Python还具有内置函数input()和raw_input()。请参阅内置函数下的Python文档。

例如

name = raw_input("Enter your name: ")   # Python 2.x

or

name = input("Enter your name: ")   # Python 3

其他人提出的答案:

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。


这将使标准输入与标准输出相呼应:

import sys
line = sys.stdin.readline()
while line:
    print line,
    line = sys.stdin.readline()

在使用sys.stdin构建所有函数的基础上,如果至少存在一个参数,还可以执行以下操作来读取参数文件,否则返回到stdin:

import sys
f = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin    
for line in f:
#     Do your stuff

并将其用作

$ python do-my-stuff.py infile.txt

or

$ cat infile.txt | python do-my-stuff.py

甚至

$ python do-my-stuff.py < infile.txt

这将使您的Python脚本表现得像许多GNU/Unix程序,如cat、grep和sed。


试试看:

import sys

print sys.stdin.read().upper()

并通过以下方式进行检查:

$ echo "Hello World" | python myFile.py

您可以从stdin读取数据,然后将输入存储到“数据”中,如下所示:

data = ""
for line in sys.stdin:
    data += line

我在读取通过管道连接到它的套接字时遇到了一些问题。当套接字关闭时,它开始在活动循环中返回空字符串。所以这是我的解决方案(我只在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


以下代码片段将帮助您(它将把所有stdin块读取到EOF,并将其转换为一个字符串):

import sys
input_str = sys.stdin.read()
print input_str.split()

关于此:

对于sys.stdin中的行:

我只是在python2.7上尝试了它(按照其他人的建议),用于一个非常大的文件,我不推荐它,正是出于上述原因(很长一段时间没有发生任何事情)。

我最终得到了一个稍微更像蟒蛇的解决方案(它适用于更大的文件):

with open(sys.argv[1], 'r') as f:
    for line in f:

然后我可以在本地运行脚本:

python myscript.py "0 1 2 3 4..." # can be a multi-line string or filename - any std.in input will work

如何在Python中读取stdin?我正在尝试进行一些代码高尔夫挑战,但它们都需要从stdin获取输入。我如何在Python中实现这一点?

您可以使用:

sys.stdin-类似文件的对象-调用sys.stdin.read()读取所有内容。input(prompt)-将可选提示传递给输出,它从stdin读取到第一个换行符,并将其删除。您必须重复这样做才能获得更多的行,在输入结束时会引发EOFError。(可能不适合打高尔夫球。)在Python 2中,这是raw_input(提示)。open(0).read()-在Python 3中,内置函数open接受文件描述符(表示操作系统IO资源的整数),0是stdin的描述符。它返回一个类似文件的对象,比如sys.stdin,这可能是您打高尔夫的最佳选择。在Python 2中,这是io.open。open('/dev/stdin').read()-类似于open(0),适用于Python 2和3,但不适用于Windows(甚至Cygwin)。fileinput.input()-在sys.argv[1:]中列出的所有文件的行上返回迭代器,如果没有给出,则返回stdin。使用类似“”的join(fileinput.input())。

当然,必须分别导入sys和fileinput。

与Python 2和3、Windows、Unix兼容的快速sys.stdin示例

例如,如果将数据传输到stdin,则只需从sys.stdin读取:

$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo

我们可以看到sys.stdin处于默认文本模式:

>>> import sys
>>> sys.stdin
<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>

文件示例

假设您有一个文件inputs.txt,我们可以接受该文件并将其写回:

python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt

更长的答案

这里是一个完整的、易于复制的演示,使用了两种方法,即内置函数、input(在Python 2中使用raw_input)和sys.stdin。数据是未修改的,因此处理是非操作的。

首先,让我们为输入创建一个文件:

$ python -c "print('foo\nbar\nbaz')" > inputs.txt

使用我们已经看到的代码,我们可以检查是否创建了文件:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt 
foo
bar
baz

下面是Python 3中sys.stdin.read的帮助:

read(size=-1, /) method of _io.TextIOWrapper instance
    Read at most n characters from stream.
    
    Read from underlying buffer until we have n characters or we hit EOF.
    If n is negative or omitted, read until EOF.

内置函数,输入(Python 2中的raw_input)

内置函数输入从标准输入读取到换行符,换行符被删除(补充打印,默认情况下添加换行符)。这会发生,直到它得到EOF(文件结束),此时它会引发EOFError。

因此,这里介绍了如何使用Python 3中的输入(或Python 2中的raw_input)从stdin读取数据,因此我们创建了一个Python模块,称为stdindemo.py:

$ python -c "print('try:\n    while True:\n        print(input())\nexcept EOFError:\n    pass')" > stdindemo.py 

让我们将其打印出来,以确保其符合我们的预期:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py 
try:
    while True:
        print(input())
except EOFError:
    pass

同样,输入读取到换行符,并从该行中删除它。print将添加新行。因此,当它们都修改输入时,它们的修改会取消。(因此,它们本质上是彼此的补充。)

当输入得到文件结尾字符时,它会引发EOFError,我们忽略它,然后退出程序。

在Linux/Unix上,我们可以通过cat:

$ cat inputs.txt | python -m stdindemo
foo
bar
baz

或者我们可以从stdin重定向文件:

$ python -m stdindemo < inputs.txt 
foo
bar
baz

我们还可以将模块作为脚本执行:

$ python stdindemo.py < inputs.txt 
foo
bar
baz

下面是Python 3内置输入的帮助:

input(prompt=None, /)
    Read a string from standard input.  The trailing newline is stripped.
    
    The prompt string, if given, is printed to standard output without a
    trailing newline before reading input.
    
    If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
    On *nix systems, readline is used if available.

标准输入

在这里,我们使用sys.stdin制作了一个演示脚本。对类似文件的对象进行迭代的有效方法是使用类似于文件的对象作为迭代器。从该输入写入stdout的补充方法是简单地使用sys.stdout.write:

$ python -c "print('import sys\nfor line in sys.stdin:\n    sys.stdout.write(line)')" > stdindemo2.py

打印出来,以确保看起来正确:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py 
import sys
for line in sys.stdin:
    sys.stdout.write(line)

并将输入重定向到文件中:

$ python -m stdindemo2 < inputs.txt
foo
bar
baz

发出命令:

$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz

高尔夫的文件描述符

由于stdin和stdout的文件描述符分别为0和1,因此我们也可以将它们传递到Python 3中打开(而不是2,请注意,我们仍然需要“w”来写入stdout)。

如果这在您的系统上有效,它将删除更多字符。

$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo

Python 2的io.open也能做到这一点,但导入需要更多的空间:

$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt 
foo
bar
baz

处理其他意见和答案

一条评论建议高尔夫使用“”.join(sys.stdin),但实际上它比sys.stdin.read()长-另外Python必须在内存中创建一个额外的列表(这是str.join在没有列表的情况下的工作方式)-作为对比:

''.join(sys.stdin)
sys.stdin.read()

最重要的答案是:

import fileinput

for line in fileinput.input():
    pass

但是,由于sys.stdin实现了文件API,包括迭代器协议,这与以下内容相同:

import sys

for line in sys.stdin:
    pass

另一个答案确实表明了这一点。请记住,如果您在解释器中执行此操作,那么如果您在Linux或Mac上,则需要执行Ctrl-d,或者在Windows上执行Ctrl-z(在Enter之后),以将文件结尾字符发送到进程。此外,该答案建议print(line)-在结尾处添加一个“\n”-改用print(line,end=“”)(如果在Python 2中,则需要使用__future_import print_function)。

fileinput的实际用例是读取一系列文件。


从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()

我非常惊讶,到目前为止没有人提到过这个黑客:

python -c "import sys; set(map(sys.stdout.write,sys.stdin))"

在python2中,您可以放弃set()调用,但这两种方法都可以


我对解决方案的问题

import sys

for line in sys.stdin:
    print(line)

如果不向stdin传递任何数据,它将永远阻塞。这就是为什么我喜欢这个答案:首先检查stdin上是否有一些数据,然后读取它

import sys
import select

# select(files to read from, files to write to, magic, timeout)
# timeout=0.0 is essential b/c we want to know the asnwer right away
if select.select([sys.stdin], [], [], 0.0)[0]:
    help_file_fragment = sys.stdin.read()
else:
    print("No data passed to stdin", file=sys.stderr)
    sys.exit(2)

argparse是一个简单的解决方案

与Python版本2和3兼容的示例:

#!/usr/bin/python

import argparse
import sys

parser = argparse.ArgumentParser()

parser.add_argument('infile',
                    default=sys.stdin,
                    type=argparse.FileType('r'),
                    nargs='?')

args = parser.parse_args()

data = args.infile.read()

您可以通过多种方式运行此脚本:

1.使用stdin

echo 'foo bar' | ./above-script.py

  或更短,方法是将echo替换为here字符串:

./above-script.py <<< 'foo bar'

2.使用文件名参数

echo 'foo bar' > my-file.data
./above-script.py my-file.data

3.通过特殊文件名使用stdin-

echo 'foo bar' | ./above-script.py -

有os.读取(0,x)它从表示stdin的0读取xbytes。这是一个无缓冲的读取,比sys.stdin.read()更低级


对于Python 3,这将是:

# Filename e.g. cat.py
import sys

for line in sys.stdin:
    print(line, end="")

这基本上是cat(1)的一种简单形式,因为它没有在每行后面添加一个换行符。您可以使用这个(在您使用chmod+x cat.py标记文件可执行文件之后),例如:

echo Hello | ./cat.py

当使用-c命令时,作为一种巧妙的方法,您可以将shell脚本命令放在以$符号开头的括号内的引号中,而不是读取stdin(在某些情况下更灵活)。

e.g.

python3 -c "import sys; print(len(sys.argv[1].split('\n')))" "$(cat ~/.goldendict/history)"

这将统计goldendict历史文件中的行数。


我使用以下方法,它从stdin返回一个字符串(我使用它进行json解析)。它可以在Windows上使用管道和提示符(尚未在Linux上测试)。提示时,两个换行符表示输入结束。

def get_from_stdin():

  lb = 0
  stdin = ''

  for line in sys.stdin:
    if line == "\n":
        lb += 1
        if lb == 2:
            break
    else:
        lb = 0
        stdin += line

  return stdin

从Python 3.8开始,您可以使用赋值表达式:

while (line := input()):
    print(line)

非阻塞、字节模式、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上测试