如何从stdin读取?

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

2049943 次浏览

以下是学习python

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

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

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

在Windows或DOS上,您可以:

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

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

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

使用#0模块:

import fileinput
for line in fileinput.input():pass

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

注意:line将包含一个尾随换行符;要删除它,请使用#1

import sys
for line in sys.stdin:print(line)

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

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

例如,

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

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

其他人提出的答案:

for line in sys.stdin:print line

非常简单和Pythonic,但必须注意,脚本将等到EOF才开始在输入行上迭代。

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

这种用例的正确脚本是:

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

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

这会将标准输入回显到标准输出:

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

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

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

并将其用作

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

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

甚至

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

这将使您的Python脚本的行为像许多GNU/Unix程序一样,例如catgrepsed

试试这个:

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

并检查它:

$ echo "Hello World" | python myFile.py

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

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

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

import sys, ossep=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:12345

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

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

关于这一点:

for line in sys.stdin:

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

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

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中读取标准输入?

我正在尝试做一些代码高尔夫挑战,但它们都需要从标准输入中获取输入。我如何在Python中获得它?

您可以使用:

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

当然,必须分别导入sysfileinput

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

例如,如果您将数据通过管道传输到stdin,您只需要从sys.stdinread

$ 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.txtfoobarbaz

以下是Python 3中关于sys.stdin.read的帮助:

read(size=-1, /) method of _io.TextIOWrapper instanceRead 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读取-因此我们创建了一个称为stdindemo.py的Python模块:

$ 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.pytry:while True:print(input())except EOFError:pass

同样,input读取直到换行符并从行中剥离它。print添加了一个换行符。因此,当它们都修改输入时,它们的修改取消了。(所以它们本质上是彼此的补充。)

input获得文件结束字符时,它会引发EOFError,我们忽略它,然后退出程序。

在Linux /Unix,我们可以从cat:

$ cat inputs.txt | python -m stdindemofoobarbaz

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

$ python -m stdindemo < inputs.txtfoobarbaz

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

$ python stdindemo.py < inputs.txtfoobarbaz

以下是Python 3中内置input的帮助:

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 atrailing 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制作一个演示脚本。迭代类文件对象的有效方法是使用类文件对象作为迭代器。从该输入写入标准输出的补充方法是简单地使用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.pyimport sysfor line in sys.stdin:sys.stdout.write(line)

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

$ python -m stdindemo2 < inputs.txtfoobarbaz

弹出一个命令:

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

高尔夫球的文件描述符

由于stdinstdout的文件描述符分别为0和1,我们也可以将它们传递给Python 3中的open(不是2,请注意我们仍然需要“w”来写入标准输出)。

如果这在您的系统上工作,它将刮掉更多的字符。

$ python -c "open(1,'w').write(open(0).read())" < inputs.txtbazbarfoo

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

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

其他评论和答案

一条评论建议''.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(在输入之后)以将文件结束字符发送到进程。此外,该答案建议print(line)-在末尾添加'\n'-使用print(line, end='')代替(如果在Python 2中,您需要from __future__ import print_function)。

fileinput的真正用例是用于读取一系列文件。

sys.stdin开始读,但是到在Windows上读取二进制数据,你需要格外小心,因为sys.stdin在文本模式下打开,它会损坏\r\n,用\n替换它们。

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

import sys
PY3K = sys.version_info >= (3, 0)
if PY3K:source = sys.stdin.bufferelse:# Python 2 on Windows opens sys.stdin in text mode, and# binary data that read from it becomes corrupted on \r\nif sys.platform == "win32":# set sys.stdin to binary modeimport os, msvcrtmsvcrt.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 sysimport 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 awayif 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)

#0简单易行

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

#!/usr/bin/python
import argparseimport 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替换为这里字符串来缩短:

./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.read(0, x)从表示标准输入的0读取xbytes。这是一个无缓冲的读取,比sys.stdin.read()更低级别

对于python3,这将是:

# Filename e.g. cat.pyimport sys
for line in sys.stdin:print(line, end="")

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

echo Hello | ./cat.py

当使用-c命令时,作为一种棘手的方式,而不是读取stdin(在某些情况下更灵活),您可以通过将shell命令放在$符号开始的括号内的引号中来传递外壳脚本命令以及您的python命令。

e. g.

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

这将计算戈登迪克特历史文件中的行数。

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

def get_from_stdin():
lb = 0stdin = ''
for line in sys.stdin:if line == "\n":lb += 1if lb == 2:breakelse:lb = 0stdin += line
return stdin

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

while (line := input()):print(line)
非阻塞,字节码,标准输入->标准输出:
# 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")continueif out is None:sys.stdout.write(b"N")continueif 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.pyNNNNNNNNN<===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: continueif not bl: breakfd1.write(bl)

在LinuxPython 3.9.2上测试