stdinからどのように読みますか?


1472

私はコードゴルフのチャレンジのいくつかを実行しようとしていますが、それらすべてから入力を取得する必要がありますstdin。Pythonでそれを取得するにはどうすればよいですか?

回答:


950

あなたはfileinputモジュールを使うことができます:

import fileinput

for line in fileinput.input():
    pass

fileinput コマンドライン引数で指定されたファイル名として指定された入力のすべての行、または引数が指定されていない場合は標準入力をループします。

注:line末尾の改行が含まれます。それを削除するにはline.rstrip()


1
@BorislavStoilovそして、この答えは「引数が指定されていない場合は標準入力」という質問に正しく答えます。
Dietmar

1
ドキュメントは標準入力にフォールバックすると述べています:「これはsys.argv [1:]にリストされているすべてのファイルの行を繰り返し、リストが空の場合はデフォルトでsys.stdinになります。ファイル名が '-'の場合は、それも置き換えられます。ファイル名の代替リストを指定するには、それをinput()の最初の引数として渡します。単一のファイル名も使用できます。
Arlo

721

それを行うにはいくつかの方法があります。

  • sys.stdinファイルのようなオブジェクトであり、関数を呼び出すことができます。readまたはreadlines、すべてを読み取りたい場合、またはすべてを読み取り、改行で自動的に分割したい場合。(import sysこれが機能するために必要です。)

  • あなたがしたい場合はプロンプトの入力をユーザーには、使用することができますraw_inputPythonの2.Xで、ちょうどinputPythonの3インチ

  • コマンドラインオプションを実際に読み取りたいだけの場合は、sys.argvリストからアクセスできます。

PythonのI / Oに関するこのWikibookの記事も参考になるでしょう。


445
import sys

for line in sys.stdin:
    print(line)

これには最後に改行文字が含まれることに注意してください。最後に改行を削除するには、line.rstrip()@ brittohalloranが言ったように使用します。


7
line.rstrip( '\ n')、それ以外の場合はすべての空白が削除されます
avp

この方法を使用して、入力ストリームがいつ終了したかをどのように知ることができますか?最終行を除き、すべての行の後にカンマを追加したい。
常習

TypeError: 'FileWrapper'オブジェクトは反復可能ではありません。
Diego Queiroz

これは正しく対処しません@avp \r\n行末
josch

228

Pythonには組み込み関数input()ともありraw_input()ます。組み込み関数の下にあるPythonのドキュメントを参照してください。

例えば、

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

または

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

7
これは1行を読み取りますが、これは実際にはOPが要求したものではありません。この質問を「開いているファイルハンドルからEOFまでの行を読み取るにはどうすればよいですか」と解釈します。
Tripleee、2015

4
OPはキーボードからの入力の読み取りを求めていません。コンテストの状況では通常、参加者に提供されるstdinからの読み取りを求めています。
chrisfs

これは私が必要としたもので、グーグルは私をここに連れてきました。おもしろいことに、rfidタグ、datetime、データベースをコード化することができましたが、ユーザーからの入力を読まなくても
大丈夫でした

204

これが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.

4
Pythonで行をカウントするための、よりメモリ効率の良い(そしておそらくより速い)方法は次のとおりprint(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), '')))です。参照wc-l.py
jfs

11
ここでの使用catは冗長です。Unixシステムの正しい呼び出しはpython countlines.py < countlines.pyです。
istepaniuk

12
「Pythonの学習」は、ユーザーにを使用するように指示する際に間違っていますreadlines()。ファイルオブジェクトは、メモリ内のすべてのデータを具体化せずに反復することを目的としています。
アーロンホール

118

Pythonでstdinからどのように読みますか?

私はいくつかのコードゴルフチャレンジを実行しようとしていますが、すべてstdinから入力を取得する必要があります。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())ます。

どちらsysfileinput当然のことながら、それぞれ、インポートする必要があります。

sys.stdinPython 2および3、Windows、Unixと互換性のある簡単な例

だけに指定する必要があるreadから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

より長い答え

これは、組み込み関数inputraw_inputPython 2で使用)との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.readPython 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.

組み込み関数inputraw_inputPython 2の場合)

組み込み関数はinput、標準入力から取り除かれる改行まで読み取ります(printデフォルトでは改行を追加する補完)。これは、EOF(ファイルの終わり)を取得するまで発生し、その時点でが発生しEOFErrorます。

したがって、以下はinput、Python 3(またはraw_inputPython 2)で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.py 
try:
    while True:
        print(input())
except EOFError:
    pass

この場合もinput、改行まで読み取り、基本的には行から取り除きます。print改行を追加します。したがって、両方が入力を変更する一方で、変更はキャンセルされます。(したがって、それらは本質的にお互いの補完です。)

そして、inputファイルの終わり文字を取得すると、EOFErrorが発生します。これを無視して、プログラムを終了します。

Linux / Unixでは、猫からパイプすることができます:

$ 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

inputPython 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ます。ファイルのようなオブジェクトを反復する効率的な方法は、ファイルのようなオブジェクトをイテレータとして使用することです。この入力から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であるためopen、Python 3に渡すこともできます(2ではなく、標準出力への書き込みには「w」が必要であることに注意してください)。

これがシステムで機能する場合、より多くの文字が削られます。

$ 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

他のコメントと回答への対応

1つのコメントは''.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- zWindows上で(後Enter工程へのファイル終了文字を送信するために)。また、その答えはprint(line)- '\n'最後にを追加する-をprint(line, end='')代わりに使用することを示唆しています(Python 2の場合はが必要になりますfrom __future__ import print_function)。

の実際のユースケースfileinputは、一連のファイルを読み取るためのものです。


103

他の人が提案した答え:

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にのみバッファリングが含まれる可能性があることが明確になりました。その結果、print呼び出しが発行される前に、バッファがいっぱいになるかEOFになるのを待つことになります。


8
for line in sys.stdin:パターンはしない EOFを待ちます。ただし、非常に小さなファイルでテストすると、応答がバッファリングされる場合があります。より多くのデータでテストして、中間結果を読み取ることを確認します。
mb。

Python 2.6.6を使用しているときにストリームから入力を取得すると、ファイルの終わりまたはバッファリングを待機しますが、3.1.3では待機しません。Note print lineは3.1.3では目覚めませんが、目覚めprint(line)ます。
ctrl-alt-delor 2012

私のpython 2.7.5「for sys.stdinの行」は、EOFまたはある程度のデータ量がバッファリングされるまでブロックします。ストリーム処理には問題ありません。行ごとの処理やユーザー入力には適していません。
Sean

2
これはlibcでのttyの検出に関連していると思われるため、対話型シェルでパイプを検出するとttyが検出されません。expect-devからのアンバッファーは、ld_preloadを介してシムを挿入するため、is_attyがtrueを返すと信じられている便利なユーティリティです(Iそれは取扱いがどのようにその者を疑うこと)
マット・フリーマン

8
@Sean:間違っています。for line in sys.stdin:「EOFまでブロック」しません。Python 2には、対応するバッファーがいっぱいになるまで行を遅延させる先読みバグがあります。これは、EOFとは無関係のバッファリングの問題です。回避策として、for line in iter(sys.stdin.readline, ''):io.open()通常のファイルに使用)を使用します。あなたは、Python 3でそれを必要としない
JFS

39

これにより、標準入力が標準出力にエコーされます。

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

31

を使用してすべての回答を基にsys.stdin、少なくとも1つの引数が存在する場合は次のようにして引数ファイルから読み取り、そうでない場合は標準入力にフォールバックすることもできます。

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スクリプトはcatgrepやのような多くのGNU / Unixプログラムのように動作しますsed


17

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により、より短く:

./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 -

入力ファイルが圧縮されている場合の対処方法は次のとおりです。stackoverflow.com / a / 33621549 / 778533add_argument('--in'スクリプトにパイプ--in -してコマンドラインに追加することもできます。PS inは、変数/属性にあまり適していません。
tommy.carstensen 2018

in変数の名前だけでなく、違法です。予約済みキーワードのargs.in.read()ため、InvalidSyntaxエラーが発生しますin。単純に名前を変更することができますinfile:ドキュメント行うargparse Pythonのようなdocs.python.org/3/library/...
ケン・コルトン

フィードバックをありがとう@ tommy.carstensen、私はちょうど答えを改善しました。メリークリスマスと新年あけましておめでとうございます;-)
olibre 2018

14

次のコードチップが役立ちます(すべてのstdinブロッキングunto EOFを1つの文字列に読み取ります)。

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

8

今のところ、このハックについて誰も言及していません。

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

python2ではあなたはset()電話を切ることができますが、それはどちらの言葉でも


1
なぜreadlinesそれを行に分割して使用するのjoinですか?あなたはただ書くことができますprint(sys.stdin.read())
ムシフィル

pythonは追加の配列を作成する必要があるため、これは必要以上のメモリを使用します。
ハリーモレノ

まあ、実際はそうではありません。なぜなら、がwrite返されNone、セットのサイズが1(=len(set([None])))より大きくなることはないからです
Uri Goren

7

これを試して:

import sys

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

そしてそれをチェックしてください:

$ echo "Hello World" | python myFile.py

7

stdinから読み取り、次のように入力を「データ」に格納できます。

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


同じことをを使用して行うことができdata = sys.stdin.read()、文字列の連結が繰り返されるという問題はありません。
ムシフィル

6

読むから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()

4

次のメソッドを使用して、stdinから文字列を返します(jsonの解析に使用します)。Windowsではパイプとプロンプトで動作します(Linuxではまだテストされていません)。プロンプトが表示されると、2つの改行が入力の終わりを示します。

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

3

私が解決策で抱えている問題

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)

ただし、この恐ろしいif条件をメソッドに隠すことを強くお勧めします。
tiktak 2017年

1
このメソッドは、プログラムの適用性を厳しく制限します。たとえば、ターミナルからのインタラクティブな入力にこれを使用することはできませんselect。または、stdinが遅いメディア(ネットワーク、CD、テープなど)上のファイルに接続されている場合にも問題が発生する可能性があります。「標準入力にデータを渡さないと、永久にブロックされます」とあなたは言った。ある問題は、私はそれがだと言うでしょう機能。ほとんどのCLIプログラム(例えばcat)はこのように機能し、期待どおりに機能します。EOFは、入力の終わりを検出するために依存すべき唯一のものです。
ムシフィル

2

パイプで接続されたソケットを介して読み取るためにこれを機能させるときに、いくつかの問題がありました。ソケットが閉じられると、アクティブなループで空の文字列を返し始めました。これが私の解決策です(私は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を指すようにすることができます


1

これに関して:

for line in sys.stdin:

私はpython 2.7(他の誰かの提案に従う)で非常に大きなファイルを試してみましたが、正確には上記の理由(長時間は何も起こらない)のため、お勧めしません。

私は少しPython的な解決策に終わりました(そしてそれはより大きなファイルで動作します):

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

質問のように、ファイルを開いても標準入力から読み込まれません。-1
アーロンホール

この場合はsys.stdin、コマンドライン引数としてスクリプトに渡します。
szeitlin

1
sys.stdinスクリプトにコマンドライン引数としてどのように渡すことができますか?引数は文字列で、ストリームはファイルのようなオブジェクトですが、同じではありません。
DeFazer 2016

@DeFazerは、その使用方法を示すために編集されました。引数は文字列ですが、Pythonのドキュメントと前述のコメントで述べたようにsys.stdin、ファイルのようなオブジェクトです
szeitlin

1

以下のための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

0

os.read(0, x) stdinを表す0からxbytesを読み取るものが存在 します。これはバッファリングされていない読み取りで、sys.stdin.read()よりも低レベルです。


0

-cトリッキーな方法としてコマンドを使用する場合は、stdin(場合によってはより柔軟な)を読む代わりに、$記号で始まる括弧内に販売コマンドを引用符で囲んで、シェルスクリプトコマンドをpythonコマンドに渡すことができます。

例えば

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

これは、goldendictの履歴ファイルの行数をカウントします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.