关于python:如何从stdin中读取?

How do you read from stdin?

我正在尝试进行一些代码高尔夫挑战,但它们都需要从stdin获取输入。我怎样才能在python中得到它?


您可以使用fileinput模块:

1
2
3
4
import fileinput

for line in fileinput.input():
    pass

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

注:line将包含一个尾随新行;要删除它,请使用line.rstrip()


有几种方法可以做到。

  • sys.stdin是一个类似文件的对象,如果您想读取所有内容或想读取所有内容并自动用换行符拆分,可以在其上调用函数readreadlines。(您需要使用import sys才能工作。)

  • 如果要提示用户输入,可以在python 2.x中使用raw_input,在python 3中只使用input

  • 如果实际上只想读取命令行选项,可以通过sys.argv列表访问它们。

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


1
2
3
4
import sys

for line in sys.stdin:
    print line


python还有内置的函数input()raw_input()。请参见内置函数下的python文档。

例如,

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

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


下面是学习python的内容:

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

在UNIX上,您可以通过执行以下操作来测试它:

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

在Windows或DOS上,您可以:

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


其他人提出的答案:

1
2
for line in sys.stdin:
  print line

它非常简单,而且是Python式的,但是必须注意的是,在开始迭代输入行之前,脚本将一直等到EOF。

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

这种用例的正确脚本是:

1
2
3
4
5
6
7
8
9
10
while 1:
    try:
        line = sys.stdin.readline()
    except KeyboardInterrupt:
        break

    if not line:
        break

    print line

更新从注释中可以清楚地看到,在python 2上,可能只涉及缓冲,因此在发出打印调用之前,您最终会等待缓冲区填充或EOF。


How do you read from stdin in Python?

I'm trying to do some of the code golf challenges, but they all require the input to be taken from stdin. How do I get that in Python?

Ok.

你可以使用:好的。

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

当然,sysfileinput都必须分别进口。好的。与python 2和3、windows、unix兼容的Quick sys.stdin示例

例如,如果将数据传输到stdin,您只需要从sys.stdin发送read:好的。

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

文件示例

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

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

更长的答案

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

首先,让我们创建一个输入文件:好的。

1
2
3
$ python -c"print('foo
bar
baz')"
> inputs.txt

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

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

下面是python 3对sys.stdin.read的帮助:好的。

1
2
3
4
5
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.

内置函数,input(python 2中的raw_input)

内置函数input从标准输入读取到新行,新行被剥离(补充print,默认情况下添加新行),直到它得到eof(文件结束),此时它将提升EOFError。好的。

因此,下面介绍如何在python 3中使用input(或者在python 2中使用raw_input)来读取stdin,因此我们创建了一个称为stdinemo.py的python模块:好的。

1
2
3
4
5
$ python -c"print('try:
    while True:
        print(input())
except EOFError:
    pass')"
> stdindemo.py

让我们把它打印出来,以确保它符合我们的预期:好的。

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

同样,input会一直读到换行符,并从换行符中删除换行符。print增加了一个新行。因此,当它们都修改输入时,它们的修改会取消。(所以它们基本上是彼此的补充。)好的。

input得到文件尾字符时,它会产生eoferror,我们忽略它,然后退出程序。好的。

在Linux/Unix上,我们可以从cat:好的。

1
2
3
4
$ cat inputs.txt | python -m stdindemo
foo
bar
baz

或者我们可以直接从stdin重定向文件:好的。

1
2
3
4
$ python -m stdindemo < inputs.txt
foo
bar
baz

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

1
2
3
4
$ python stdindemo.py < inputs.txt
foo
bar
baz

下面是关于python 3内置的input的帮助:好的。

1
2
3
4
5
6
7
8
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

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

1
2
3
$ python -c"print('import sys
for line in sys.stdin:
    sys.stdout.write(line)')"
> stdindemo2.py

把它打印出来以确保它看起来正确:好的。

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

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

1
2
3
4
$ python -m stdindemo2 < inputs.txt
foo
bar
baz

高尔菲德指挥:好的。

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

高尔夫文件描述符

由于stdinstdout的文件描述符分别为0和1,因此我们也可以在python 3中将它们传递给open(而不是2,注意我们仍然需要"w"来写入stdout)。好的。

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

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

python 2的io.open也可以做到这一点,但是导入需要更多的空间:好的。

1
2
3
4
$ 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)的工作方式),以形成对比:好的。

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

最重要的答案是:好的。

1
2
3
4
import fileinput

for line in fileinput.input():
    pass

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

1
2
3
4
import sys

for line in sys.stdin:
    pass

另一个答案确实表明了这一点。请记住,如果在解释器中执行此操作,那么如果在Linux或Mac上,则需要执行ctrl d;如果在Windows上,则需要执行ctrl zabbkbd(在enter之后),以便将文件结尾字符发送到进程。另外,这个答案也暗示了print(line),它在最终使用中添加了'
'
,而不是print(line, end='')(如果在python 2中,您将需要from __future__ import print_function)。好的。

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


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

1
2
3
4
5
import sys
line = sys.stdin.readline()
while line:
    print line,
    line = sys.stdin.readline()

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

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

并将其用作

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

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

甚至

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

这将使您的python脚本的行为类似于许多GNU/Unix程序,如catgrepsed


下面的代码芯片将帮助您(它将把所有stdin阻塞读取到EOF中的一个字符串中):

1
2
3
import sys
input_str = sys.stdin.read()
print input_str.split()

argparse是一个简单的解决方案

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/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

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

&emsp;或更短,用这里的字符串替换echo

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

2。使用文件名参数

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

三。通过特殊文件名-使用stdin

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


您可以从stdin读取,然后将输入存储到"data"中,如下所示:

1
2
3
data =""
for line in sys.stdin:
    data += line


试试这个:

1
2
3
import sys

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

并检查:

1
$ echo"Hello World" | python myFile.py

我很惊讶到目前为止还没有人提到这个黑客:

1
python -c"import sys;print (''.join([l for l in sys.stdin.readlines()]))"

与python2和python3兼容


sys.stdin读取,但要在Windows上读取二进制数据,需要格外小心,因为sys.stdin在文本模式下打开,它会损坏

,用
替换它们。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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


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

我有解决问题的办法

1
2
3
4
import sys

for line in sys.stdin:
    print(line)

如果不向stdin传递任何数据,它将永远阻塞。这就是我喜欢这个答案的原因:首先检查stdin上是否有数据,然后阅读它。这就是我最后所做的:

1
2
3
4
5
6
7
8
9
10
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)


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

1
2
3
4
5
6
7
import sys, os
sep=os.linesep

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

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

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

您可以使用telnet或将浏览器指向localhost:12345来调用它。


关于这一点:

for line in sys.stdin:

我刚刚在python 2.7上(根据别人的建议)尝试了一个非常大的文件,我不推荐它,正是因为上面提到的原因(很长时间内没有发生任何事情)。

最后我得到了一个稍微多一点的Python式解决方案(它适用于更大的文件):

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

然后我可以在本地运行脚本,如下所示:

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


1
2
3
n = int(raw_input())
for i in xrange(n):
    name, number = raw_input().split()


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