我正在尝试做一些代码高尔夫挑战,但它们都需要从stdin
. 我如何在 Python 中得到它?
23 回答
您可以使用该fileinput
模块:
import fileinput
for line in fileinput.input():
pass
fileinput
将遍历输入中指定为命令行参数中给出的文件名的所有行,如果没有提供参数,则循环遍历标准输入。
注意:line
将包含一个尾随换行符;删除它使用line.rstrip()
有几种方法可以做到这一点。
sys.stdin
是一个类似文件的对象,您可以在其上调用函数read
,或者readlines
如果您想读取所有内容,或者您想要读取所有内容并自动用换行符分割它。(您需import sys
要这样做。)如果要提示用户输入,可以
raw_input
在 Python 2.X中使用,也可以input
在 Python 3 中使用。如果您实际上只是想阅读命令行选项,则可以通过sys.argv列表访问它们。
您可能会发现这篇关于 Python 中 I/O 的 Wikibook 文章也是有用的参考。
import sys
for line in sys.stdin:
print(line)
请注意,这将在末尾包含一个换行符。要在最后删除换行符,请line.rstrip()
按照@brittohalloran 所说使用。
Python 还具有内置函数input()
和raw_input()
. 请参阅内置函数下的 Python 文档。
例如,
name = raw_input("Enter your name: ") # Python 2.x
或者
name = input("Enter your name: ") # Python 3
这里来自学习 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.
你如何在 Python 中读取标准输入?
我正在尝试做一些代码高尔夫挑战,但它们都需要从标准输入中获取输入。我如何在 Python 中得到它?
您可以使用:
sys.stdin
- 类似文件的对象 - 调用sys.stdin.read()
读取所有内容。input(prompt)
- 将可选提示传递给输出,它从标准输入读取到第一个换行符,然后将其剥离。您必须反复执行此操作才能获得更多行,在输入结束时它会引发 EOFError。(可能不适合打高尔夫球。)在 Python 2 中,这是rawinput(prompt)
.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
分别导入。
sys.stdin
与 Python 2 和 3、Windows、Unix 兼容的快速示例
您只需要read
from 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
(raw_input
在 Python 2 中使用)和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
这是sys.stdin.read
来自 Python 3 的帮助:
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
(raw_input
在 Python 2 中)
内置函数input
从标准输入读取到换行符,该换行符被剥离(补充print
,默认情况下添加换行符。)这种情况会发生,直到它获得 EOF(文件结束),此时它会引发EOFError
.
因此,以下是如何input
在 Python 3(或raw_input
Python 2)中使用从标准输入读取的方法——因此我们创建了一个称为 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.py
try:
while True:
print(input())
except EOFError:
pass
再次,input
读取到换行符并基本上将其从行中剥离。print
添加一个换行符。因此,当他们都修改输入时,他们的修改会取消。(所以它们本质上是彼此的互补。)
当input
获得文件结尾字符时,它会引发 EOFError,我们忽略它然后退出程序。
在 Linux/Unix 上,我们可以从 cat 管道:
$ cat inputs.txt | python -m stdindemo
foo
bar
baz
或者我们可以从标准输入重定向文件:
$ python -m stdindemo < inputs.txt
foo
bar
baz
我们也可以将模块作为脚本执行:
$ python stdindemo.py < inputs.txt
foo
bar
baz
input
以下是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
这里我们使用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.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,我们也可以open
在 Python 3 中将它们传递给(不是 2,注意我们仍然需要 'w' 来写入标准输出)。
如果这适用于您的系统,它将减少更多字符。
$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo
Python 2io.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
另一个答案确实表明了这一点。请记住,如果您在解释器中执行此操作,则需要Ctrl-d如果您在 Linux 或 Mac 上,或者Ctrl-z在 Windows(在 之后Enter)将文件结尾字符发送到进程。此外,该答案建议print(line)
- 它'\n'
在最终添加 a - 使用print(line, end='')
(如果在 Python 2 中,您将需要from __future__ import print_function
)。
的真正用例fileinput
是读取一系列文件。
其他人提出的答案:
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 sys
line = sys.stdin.readline()
while line:
print line,
line = sys.stdin.readline()
在所有使用的答案的基础上sys.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
或者
$ cat infile.txt | python do-my-stuff.py
甚至
$ python do-my-stuff.py < infile.txt
这将使您的 Python 脚本的行为类似于许多 GNU/Unix 程序,例如cat
,grep
和sed
.
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
./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 -
以下代码片将为您提供帮助(它将所有 stdin 阻塞读取EOF
到一个字符串中):
import sys
input_str = sys.stdin.read()
print input_str.split()
我很惊讶到目前为止没有人提到这个黑客:
python -c "import sys; set(map(sys.stdout.write,sys.stdin))"
在 python2 中,您可以挂断set()
电话,但无论哪种方式
尝试这个:
import sys
print sys.stdin.read().upper()
并检查:
$ echo "Hello World" | python myFile.py
您可以从标准输入读取,然后将输入存储到“数据”中,如下所示:
data = ""
for line in sys.stdin:
data += line
我使用以下方法,它从标准输入返回一个字符串(我用它来解析 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
从 读取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.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 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
我有解决方案的问题
import sys
for line in sys.stdin:
print(line)
是如果您不将任何数据传递给标准输入,它将永远阻塞。这就是我喜欢这个答案的原因:先检查标准输入是否有一些数据,然后再阅读。这就是我最终做的事情:
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)
从 Python 3.8 开始,您可以使用赋值表达式:
while (line := input()):
print(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:12345
关于这一点:
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
使用-c
命令时,作为一种棘手的方式,您可以通过将 shell 命令放在以符号stdin
开头的括号内的引号中,而不是阅读(在某些情况下更灵活),也可以将 shell 脚本命令传递给您的 python 命令。$
例如
python3 -c "import sys; print(len(sys.argv[1].split('\n')))" "$(cat ~/.goldendict/history)"
这将计算 Goldendict 历史文件中的行数。
有
os.read(0, x)
从代表标准输入的 0 读取 xbytes。这是一个无缓冲读取,比 sys.stdin.read() 更低级别