Bagaimana Anda membaca dari stdin?


1473

Saya mencoba melakukan beberapa tantangan kode golf , tetapi semuanya membutuhkan input untuk diambil stdin. Bagaimana saya mendapatkannya dengan Python?

Jawaban:


951

Anda bisa menggunakan fileinputmodul:

import fileinput

for line in fileinput.input():
    pass

fileinput akan mengulangi semua baris dalam input yang ditentukan sebagai nama file yang diberikan dalam argumen baris perintah, atau input standar jika tidak ada argumen yang diberikan.

Catatan: lineakan berisi baris tambahan tambahan; untuk menghapusnya gunakanline.rstrip()


1
@ BorislavStoilov Dan jawaban ini benar menjawab pertanyaan: "atau input standar jika tidak ada argumen yang diberikan".
Dietmar

1
Dokumentasi menyatakan bahwa ia mundur ke stdin: "Ini beralih ke baris semua file yang terdaftar di sys.argv [1:], default ke sys.stdin jika daftar kosong. Jika nama file adalah '-', itu juga diganti oleh sys.stdin. Untuk menentukan daftar nama file alternatif, berikan sebagai argumen pertama untuk memasukkan (). Nama file tunggal juga diperbolehkan. "
Arlo

721

Ada beberapa cara untuk melakukannya.

  • sys.stdinadalah objek seperti file tempat Anda dapat memanggil fungsi readatau readlinesjika Anda ingin membaca semuanya atau Anda ingin membaca semuanya dan membaginya dengan baris baru secara otomatis. (Anda perlu agar import sysini berfungsi.)

  • Jika Anda ingin meminta input dari pengguna, Anda bisa menggunakan raw_inputPython 2.X, dan hanya inputdi Python 3.

  • Jika Anda sebenarnya hanya ingin membaca opsi baris perintah, Anda dapat mengaksesnya melalui daftar sys.argv .

Anda mungkin akan menemukan artikel Wikibook ini di I / O dengan Python sebagai referensi yang berguna juga.


445
import sys

for line in sys.stdin:
    print(line)

Perhatikan bahwa ini akan menyertakan karakter baris baru di akhir. Untuk menghapus baris baru di bagian akhir, gunakan line.rstrip()seperti yang dikatakan @brittohalloran.


7
line.rstrip ('\ n'), jika tidak maka akan menghapus semua spasi putih
avp

menggunakan metode ini, bagaimana kita tahu kapan input stream berakhir? Saya ingin menambahkan koma setelah setiap baris kecuali untuk baris terakhir.
kecanduan

Saya menerima: TypeError: objek 'FileWrapper' tidak dapat diubah.
Diego Queiroz

@avp ini tidak akan menangani \r\nakhiran dengan benar
josch

228

Python juga memiliki fungsi bawaan input()dan raw_input(). Lihat dokumentasi Python di bawah Fungsi Bawaan .

Sebagai contoh,

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

atau

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

7
Ini berbunyi satu baris, yang sebenarnya bukan pertanyaan OP. Saya menafsirkan pertanyaan sebagai "bagaimana saya membaca banyak baris dari pegangan file terbuka sampai EOF?"
tripleee

4
OP tidak meminta untuk membaca input dari keyboard, Dia meminta untuk membaca dari stdin yang dalam situasi kontes biasanya diberikan kepada para kontestan.
chrisfs

ini yang saya butuhkan, google membawa saya ke sini. Menariknya saya berhasil kode tag rfid, datetime, database, tetapi tidak pernah repot membaca input dari pengguna lol
clockw0rk

204

Ini dari Learning Python :

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

Di Unix, Anda dapat mengujinya dengan melakukan sesuatu seperti:

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

Di Windows atau DOS, Anda akan melakukan:

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

4
Berikut adalah memori yang lebih efisien (dan mungkin lebih cepat) cara untuk menghitung baris dalam Python: print(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), ''))). lihatwc-l.py
jfs

11
Penggunaan di catsini berlebihan. Doa yang benar untuk sistem Unix adalah python countlines.py < countlines.py.
istepaniuk

12
"Belajar Python" salah dalam mengarahkan pengguna untuk menggunakan readlines(). Objek file dimaksudkan untuk diulang tanpa mematerialisasi semua data dalam memori.
Aaron Hall

118

Bagaimana Anda membaca dari stdin dengan Python?

Saya mencoba melakukan beberapa tantangan kode golf, tetapi mereka semua membutuhkan input yang akan diambil dari stdin. Bagaimana saya mendapatkannya dengan Python?

Kamu bisa menggunakan:

  • sys.stdin- Objek seperti file - panggilan sys.stdin.read()untuk membaca semuanya.
  • input(prompt)- berikan prompt opsional untuk output, ia membaca dari stdin hingga baris baru pertama, yang dilucuti. Anda harus melakukan ini berulang kali untuk mendapatkan lebih banyak baris, pada akhir input yang memunculkan EOFError. (Mungkin tidak bagus untuk bermain golf.) Dalam Python 2, ini rawinput(prompt).
  • open(0).read()- Dalam Python 3, fungsi builtin openmenerima deskriptor file (integer yang mewakili sumber daya sistem operasi IO), dan 0 adalah deskriptor dari stdin. Ini mengembalikan objek seperti file sys.stdin- mungkin taruhan terbaik Anda untuk bermain golf. Dalam Python 2, ini io.open.
  • open('/dev/stdin').read()- Mirip dengan open(0), bekerja pada Python 2 dan 3, tetapi tidak pada Windows (atau bahkan Cygwin).
  • fileinput.input()- Mengembalikan iterator melalui baris di semua file yang terdaftar di sys.argv[1:], atau stdin jika tidak diberikan. Gunakan seperti ''.join(fileinput.input()).

Keduanya sysdan fileinputharus diimpor, masing-masing, tentu saja.

sys.stdinContoh cepat kompatibel dengan Python 2 dan 3, Windows, Unix

Anda hanya perlu readdari sys.stdin, misalnya, jika Anda mengirim data ke stdin:

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

Kita dapat melihat bahwa sys.stdinitu dalam mode teks standar:

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

contoh file

Katakanlah Anda memiliki file,, inputs.txtkami dapat menerima file itu dan menulisnya kembali:

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

Jawaban yang lebih panjang

Berikut ini adalah demo lengkap dan mudah ditiru, menggunakan dua metode, fungsi builtin, input(digunakan raw_inputdalam Python 2), dan sys.stdin. Data tidak dimodifikasi, sehingga pemrosesan adalah non-operasi.

Untuk memulainya, mari buat file untuk input:

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

Dan menggunakan kode yang telah kita lihat, kita dapat memeriksa bahwa kita telah membuat file:

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

Ini bantuan sys.stdin.readdari 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.

Fungsi bawaan, input( raw_inputdalam Python 2)

Fungsi builtin inputmembaca dari input standar hingga baris baru, yang dilucuti (melengkapi print, yang menambahkan baris baru secara default.) Ini terjadi sampai mendapat EOF (End Of File), pada titik mana ia memunculkan EOFError.

Jadi, inilah cara Anda dapat menggunakan inputPython 3 (atau raw_inputPython 2) untuk membaca dari stdin - jadi kami membuat modul Python yang kami sebut stdindemo.py:

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

Dan mari kita cetak kembali untuk memastikannya seperti yang kita harapkan:

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

Sekali lagi, inputbaca sampai baris baru dan pada dasarnya menghapusnya dari baris. printmenambahkan baris baru. Jadi sementara mereka berdua memodifikasi input, modifikasi mereka dibatalkan. (Jadi mereka pada dasarnya saling melengkapi.)

Dan ketika inputmendapatkan karakter end-of-file, itu menimbulkan EOFError, yang kita abaikan dan kemudian keluar dari program.

Dan di Linux / Unix, kita dapat melakukan pipe dari cat:

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

Atau kita bisa mengarahkan file dari stdin:

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

Kami juga dapat menjalankan modul sebagai skrip:

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

Inilah bantuan pada builtin inputdari 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

Di sini kami membuat skrip demo menggunakan sys.stdin. Cara efisien untuk beralih pada objek seperti file adalah dengan menggunakan objek seperti file sebagai iterator. Metode komplementer untuk menulis ke stdout dari input ini adalah dengan menggunakan sys.stdout.write:

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

Cetak kembali untuk memastikan tampilannya benar:

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

Dan mengarahkan input ke file:

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

Dimasukkan ke dalam perintah:

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

File Deskriptor untuk Bermain Golf

Karena file deskriptor untuk stdindan stdoutmasing-masing adalah 0 dan 1, kita juga dapat meneruskannya ke opendalam Python 3 (bukan 2, dan perhatikan bahwa kita masih membutuhkan 'w' untuk menulis ke stdout).

Jika ini bekerja pada sistem Anda, itu akan memangkas lebih banyak karakter.

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

Python 2 io.openmelakukan ini juga, tetapi impor membutuhkan lebih banyak ruang:

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

Mengatasi komentar dan jawaban lain

Satu komentar menyarankan ''.join(sys.stdin)untuk bermain golf tapi itu sebenarnya lebih lama dari sys.stdin.read () - ditambah Python harus membuat daftar tambahan di memori (itulah cara str.joinkerjanya ketika tidak diberi daftar) - untuk kontras:

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

Jawaban teratas menyarankan:

import fileinput

for line in fileinput.input():
    pass

Tapi, karena sys.stdinmengimplementasikan file API, termasuk protokol iterator, itu sama saja dengan ini:

import sys

for line in sys.stdin:
    pass

Jawaban lain tidak menyarankan ini. Ingatlah bahwa jika Anda melakukannya dalam juru bahasa, Anda harus melakukan Ctrl- djika Anda menggunakan Linux atau Mac, atau Ctrl- zpada Windows (setelah Enter) untuk mengirim karakter akhir file ke proses. Juga, jawaban itu menyarankan print(line)- yang menambahkan a '\n'ke akhir - gunakan print(line, end='')sebagai gantinya (jika dalam Python 2, Anda akan perlu from __future__ import print_function).

Kasus penggunaan sebenarnya fileinputadalah untuk membaca dalam serangkaian file.


103

Jawaban yang diajukan oleh orang lain:

for line in sys.stdin:
  print line

sangat sederhana dan pythonic, tetapi harus dicatat bahwa skrip akan menunggu sampai EOF sebelum mulai beralih pada baris input.

Ini berarti bahwa tail -f error_log | myscript.pytidak akan memproses garis seperti yang diharapkan.

Skrip yang benar untuk kasus penggunaan seperti itu adalah:

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

    if not line:
        break

    print line

MEMPERBARUI
Dari komentar telah dihapus bahwa pada python 2 hanya mungkin ada buffering yang terlibat, sehingga Anda akhirnya menunggu buffer untuk mengisi atau EOF sebelum panggilan cetak dikeluarkan.


8
The for line in sys.stdin:Pola tidak menunggu EOF. Tetapi jika Anda menguji pada file yang sangat kecil, respons mungkin mendapat buffered. Uji dengan lebih banyak data untuk melihat bahwa itu membaca hasil antara.
mb.

Saya mendapatkan menunggu End Of File atau buffering, ketika mengambil input dari aliran ketika menggunakan python 2.6.6, tetapi dengan 3.1.3 saya tidak. Note print linetidak terbangun pada 3.1.3, tetapi print(line)tidak.
ctrl-alt-delor

python 2.7.5 "untuk baris di sys.stdin", memblokir hingga EOF atau sejumlah data masuk akal telah disangga. Baik untuk pemrosesan aliran. Tidak baik untuk pemrosesan baris demi baris atau input pengguna.
Sean

2
Saya menduga ini terkait dengan deteksi tty di libc, jadi ketika Anda memasang pipa pada shell interaktif, ia mendeteksi tidak ada tty, unbuffer dari expect-dev adalah utilitas berguna yang saya percaya menyuntikkan shim melalui ld_preload sehingga is_atty mengembalikan true (I curiga itulah cara menyerahkannya)
Mâtt Frëëman

8
@Sean: salah . for line in sys.stdin:tidak "memblokir sampai EOF". Ada bug baca-depan di Python 2 yang menunda baris sampai buffer yang sesuai penuh. Ini adalah masalah buffering yang tidak terkait dengan EOF. Untuk mengatasinya, gunakan for line in iter(sys.stdin.readline, ''):(gunakan io.open()untuk file biasa). Anda tidak membutuhkannya di Python 3.
jfs

39

Ini akan menggemakan input standar ke output standar:

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

31

Membangun semua jawaban menggunakan sys.stdin, Anda juga dapat melakukan sesuatu seperti berikut untuk membaca dari file argumen jika setidaknya ada satu argumen, dan kembali ke stdin sebaliknya:

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

dan gunakan itu juga

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

atau

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

atau bahkan

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

Itu akan membuat skrip Python Anda berperilaku seperti banyak program GNU / Unix seperti cat, grepdansed .


17

argparse adalah solusi mudah

Contoh kompatibel dengan versi Python 2 dan 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()

Anda dapat menjalankan skrip ini dengan banyak cara:

1. Menggunakan stdin

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

  atau lebih pendek dengan mengganti echodengan sini tali :

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

2. Menggunakan argumen nama file

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

3. Menggunakan stdinmelalui nama file khusus-

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

Berikut ini adalah jawaban tentang apa yang harus dilakukan, jika file input dikompresi: stackoverflow.com/a/33621549/778533 Kita juga dapat melakukan add_argument('--in'dan pipa ke skrip dan menambahkan --in -ke baris perintah. PS inbukan nama yang sangat bagus untuk variabel / atribut.
tommy.carstensen

inbukan hanya nama buruk untuk variabel, itu ilegal. args.in.read()akan meningkatkan kesalahan InvalidSyntax karena inkata kunci yang dipesan. Cukup ganti nama menjadi infileseperti python argparse docs lakukan: docs.python.org/3/library/…
Ken Colton

Terima kasih @tommy.carstensen atas tanggapan Anda, saya baru saja memperbaiki jawabannya. Selamat Natal dan Tahun Baru ;-)
olibre

14

Chip kode berikut akan membantu Anda (ini akan membaca semua stdin yang menghalangi EOF, menjadi satu string):

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

8

Saya cukup kagum tidak ada yang menyebutkan peretasan ini sejauh ini:

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

di python2 Anda bisa menghentikan set()panggilan, tetapi akan kata baik


1
Mengapa menggunakan readlinesitu dibagi menjadi beberapa baris dan sekali joinlagi? Anda bisa menulisprint(sys.stdin.read())
musiphil

Ini akan menggunakan lebih banyak memori daripada yang dibutuhkan karena python perlu membangun array tambahan.
Harry Moreno

Yah, tidak juga, karena writekembali None, dan ukuran yang ditetapkan tidak akan pernah lebih besar dari 1 ( =len(set([None])))
Uri Goren

7

Coba ini:

import sys

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

dan periksa dengan:

$ echo "Hello World" | python myFile.py


6

Baca dari sys.stdin, tetapi untuk membaca data biner pada Windows , Anda harus ekstra hati-hati, karena sys.stdinada yang dibuka dalam mode teks dan akan rusak \r\nmenggantinya dengan\n .

Solusinya adalah mengatur mode ke biner jika Windows + Python 2 terdeteksi, dan menggunakan 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

Saya menggunakan metode berikut, ia mengembalikan string dari stdin (saya menggunakannya untuk parsing json). Ini bekerja dengan pipa dan meminta pada Windows (belum diuji di Linux). Saat diminta, dua jeda baris menunjukkan akhir input.

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

Masalah yang saya miliki dengan solusi

import sys

for line in sys.stdin:
    print(line)

adalah bahwa jika Anda tidak meneruskan data apa pun ke stdin, itu akan diblokir selamanya. Itu sebabnya saya suka jawaban ini : periksa apakah ada beberapa data tentang stdin pertama, dan kemudian bacalah. Inilah yang akhirnya saya lakukan:

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)

Saya sangat merekomendasikan menyembunyikan ini mengerikan jika kondisi menjadi metode sekalipun.
tiktak

1
Metode ini membatasi penerapan program secara serius: misalnya, Anda tidak dapat menggunakan ini untuk input interaktif dari terminal, karena input tersebut hampir tidak akan pernah "siap" ketika selectdipanggil; atau Anda juga bisa menghadapi masalah jika stdin terhubung ke file pada media yang lambat (jaringan, CD, tape, dll.). Anda mengatakan bahwa "jika Anda tidak meneruskan data apa pun ke stdin, itu akan diblokir selamanya." adalah masalah , tapi saya akan mengatakan itu fitur . Sebagian besar program CLI (mis. cat) Bekerja dengan cara ini, dan mereka diharapkan untuk melakukannya. EOF adalah satu-satunya hal yang harus Anda andalkan untuk mendeteksi akhir input.
musiphil

2

Saya memiliki beberapa masalah ketika membuat ini berfungsi untuk membaca soket yang disalurkan ke sana. Ketika soket ditutup, ia mulai mengembalikan string kosong dalam loop aktif. Jadi ini solusi saya untuk itu (yang hanya saya uji di linux, tapi saya harap ini berhasil di semua sistem lain)

import sys, os
sep=os.linesep

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

Jadi, jika Anda mulai mendengarkan pada soket, itu akan berfungsi dengan baik (misalnya dalam bash):

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

Dan Anda dapat menyebutnya dengan telnet atau arahkan browser ke localhost: 12345


1

Mengenai hal ini:

for line in sys.stdin:

Saya baru mencobanya di python 2.7 (mengikuti saran orang lain) untuk file yang sangat besar, dan saya tidak merekomendasikannya, justru karena alasan yang disebutkan di atas (tidak ada yang terjadi untuk waktu yang lama).

Saya berakhir dengan solusi pythonic yang sedikit lebih (dan ini bekerja pada file yang lebih besar):

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

Kemudian saya dapat menjalankan skrip secara lokal sebagai:

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

Membuka file bukan membaca dari stdin, seperti pertanyaan yang diajukan. -1
Aaron Hall

Dalam hal ini saya menyampaikan sys.stdinsebagai argumen baris perintah untuk skrip.
szeitlin

1
Bagaimana Anda bisa meneruskan sys.stdinsebagai argumen baris perintah ke skrip? Argumen adalah string dan stream adalah objek seperti file, mereka tidak sama.
DeFazer

@DeFazer diedit untuk menunjukkan cara menggunakannya. Argumen adalah string, ya, tetapi seperti python docs dan saya sebutkan dalam komentar sebelumnya di atas, sys.stdinadalah objek seperti file
szeitlin

1

Untuk Python 3 itu adalah:

# Filename e.g. cat.py
import sys

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

Ini pada dasarnya adalah bentuk sederhana kucing (1), karena tidak menambahkan baris baru setelah setiap baris. Anda dapat menggunakan ini (setelah Anda menandai file yang dapat dieksekusi menggunakan chmod +x cat.pyseperti:

echo Hello | ./cat.py

0

Ada os.read(0, x) yang membaca xbytes dari 0 yang mewakili stdin. Ini adalah bacaan tidak terbaca, lebih rendah daripada sys.stdin.read ()


0

Saat menggunakan -cperintah, sebagai cara yang rumit, alih-alih membaca stdin(dan lebih fleksibel dalam beberapa kasus), Anda dapat meneruskan perintah skrip shell juga ke perintah python Anda dengan memasukkan perintah jual dalam tanda kutip di dalam tanda kurung yang dimulai oleh$ tanda.

misalnya

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

Ini akan menghitung jumlah baris dari file sejarah goldendict.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.