Stdin'den nasıl okuyorsun?


1470

Bazı kod golf zorlukları yapmaya çalışıyorum , ama hepsi alınacak girişi gerektirir stdin. Bunu Python'da nasıl edinebilirim?

Yanıtlar:


950

fileinputModülü kullanabilirsiniz :

import fileinput

for line in fileinput.input():
    pass

fileinput komut satırı bağımsız değişkenlerinde verilen dosya adları olarak belirtilen girdideki tüm satırlar veya bağımsız değişken sağlanmamışsa standart girdi arasında döngü yapar.

Not: linesondaki bir yeni satır içerir; kaldırmak için kullanınline.rstrip()


1
@BorislavStoilov Ve bu cevap şu soruyu doğru bir şekilde cevaplıyor: "veya herhangi bir argüman verilmemişse standart girdi".
Dietmar

1
Belgeler, stdin'e geri döndüğünü belirtiyor: "Bu, sys.argv [1:] 'de listelenen tüm dosyaların satırları üzerinden yinelenir ve liste boşsa varsayılan olarak sys.stdin olarak değiştirilir. Bir dosya adı' - 'ise, bunun yerine de Alternatif bir dosya adı listesi belirtmek için listeyi input () öğesine ilk argüman olarak iletin. Tek bir dosya adına da izin verilir. "
Arlo

721

Bunu yapmanın birkaç yolu var.

  • sys.stdinişlevleri çağırabileceğiniz readya readlinesda her şeyi okumak istiyorsanız ya da her şeyi okumak ve otomatik olarak satırsonuna göre bölmek istediğiniz dosya benzeri bir nesnedir . (Bunun import sysçalışması için gerekir .)

  • İsterseniz istemi kullanıcıdan giriş kullanabileceğiniz raw_inputPython 2.x ve sadece inputPython 3'te.

  • Sadece komut satırı seçeneklerini okumak istiyorsanız, bunlara sys.argv listesinden erişebilirsiniz .

Muhtemelen Python'daki I / O hakkındaki bu Wikibook makalesini de yararlı bir referans olarak bulacaksınız .


445
import sys

for line in sys.stdin:
    print(line)

Bunun sonunda bir satırsonu karakteri içereceğini unutmayın. line.rstrip()Sondaki yeni satırı kaldırmak için, @brittohalloran'ın dediği gibi kullanın .


7
line.rstrip ('\ n'), aksi takdirde tüm boşlukları bırakacaktır
avp

bu yöntemi kullanarak, giriş akışının ne zaman sona erdiğini nasıl biliyoruz? Son satır için her satır istisnasından sonra virgül eklemek istiyorum .
bağımlısı

Aldım: TypeError: 'FileWrapper' nesnesi yinelenemez.
Diego Queiroz

@avp bu \r\nsatır sonlarıyla doğru bir şekilde ilgilenmeyecek
josch

228

Python ayrıca yerleşik işlevlere sahiptir input()ve raw_input(). Yerleşik İşlevler altındaki Python belgelerine bakın .

Örneğin,

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

veya

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

7
Bu, OP'nin gerçekten sorduğu şey değil, tek bir satır okur. Soruyu "Açık dosya tanıtıcısından EOF'a kadar bir grup satırı nasıl okuyabilirim?"
tripleee

4
OP bir klavyeden girdi okumak istemiyor, bir yarışma durumunda genellikle yarışmacılara verilen stdin'den okumak istiyor.
chrisfs

İhtiyacım olan bu, google beni buraya getirdi. ilginç bir şekilde rfid etiketleri, datetime, veritabanları kodlamayı başardı, ama asla lol kullanıcı girişini okumak için rahatsız
clockw0rk

204

İşte Python Öğrenme'den :

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

Unix'te şöyle bir şey yaparak test edebilirsiniz:

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

Windows veya DOS'ta şunları yaparsınız:

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

4
İşte (belki daha hızlı ve) verimli bir daha bellek Python satırları saymak için yolu şudur: print(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), ''))). bkz.wc-l.py
jfs

11
Kullanımı catburada gereksiz olduğunu. Unix sistemleri için doğru çağrı python countlines.py < countlines.py.
istepaniuk

12
"Öğrenme Python" kullanıcıları kullanmaya yönlendirmede yanlıştır readlines(). Dosya nesneleri, bellekteki tüm verileri gerçekleştirmeden yinelenmelidir.
Aaron Hall

118

Python'da stdin'den nasıl okuyorsun?

Bazı kod golf zorlukları yapmaya çalışıyorum, ama hepsi giriş stdin alınmasını gerektirir. Bunu Python'da nasıl edinebilirim?

Kullanabilirsiniz:

  • sys.stdin- Dosya benzeri bir nesne - sys.stdin.read()her şeyi okumak için arayın .
  • input(prompt)- çıktı almak için isteğe bağlı bir istemi iletin, stdin'den ilk satır satırına kadar okur. Daha fazla satır elde etmek için bunu tekrar tekrar yapmanız gerekir, girişin sonunda EOFError'u yükseltir. (Muhtemelen golf için harika değil.) Python 2'de bu rawinput(prompt).
  • open(0).read()- Python 3'te yerleşik işlev open, dosya tanımlayıcılarını (işletim sistemi IO kaynaklarını temsil eden tamsayılar) kabul eder ve 0, tanımlayıcıdır stdin. Dosya benzeri bir nesne döndürür sys.stdin- muhtemelen golf için en iyi bahistir. Python 2'de bu io.open.
  • open('/dev/stdin').read()- open(0)Python 2 ve 3'te çalışır, ancak Windows (hatta Cygwin) üzerinde çalışmaz.
  • fileinput.input()- listelenen tüm dosyalarda satırlar üzerinden yineleyici sys.argv[1:]veya verilmemişse stdin döndürür . Gibi kullanın ''.join(fileinput.input()).

Her ikisi de sysve fileinputelbette sırasıyla ithal edilmelidir.

sys.stdinPython 2 ve 3, Windows, Unix ile uyumlu hızlı örnekler

Sadece gerek readdan sys.stdinsen boru veri stdin'i eğer, örneğin,:

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

Bunun sys.stdinvarsayılan metin modunda olduğunu görebiliriz :

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

dosya örneği

Bir dosyanız inputs.txtolduğunu varsayalım, bu dosyayı kabul edebilir ve geri yazabiliriz:

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

Daha uzun cevap

İşte, iki yöntem kullanarak, yerleşik işlev input( raw_inputPython 2'de kullanın ) ve sys.stdin. Veriler değiştirilmez, bu nedenle işlem bir işlem değildir.

Başlangıç ​​olarak, girdiler için bir dosya oluşturalım:

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

Daha önce gördüğümüz kodu kullanarak dosyayı oluşturduğumuzu kontrol edebiliriz:

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

İşte sys.stdin.readPython 3'ten yardım :

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.

Yerleşik işlev, input( raw_inputPython 2'de)

Yerleşik işlev input, standart girdiden yeni bir satıra kadar okur, bu satır (tamamlayıcı print, varsayılan olarak yeni satır ekler.) EOF (Dosya Sonu) alana kadar yükselir EOFError.

Böylece, stdin'den okumak için inputPython 3'te (veya raw_inputPython 2'de) şu şekilde kullanabilirsiniz - böylece stdindemo.py dediğimiz bir Python modülü yaratırız:

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

Ve beklediğimizden emin olmak için tekrar yazdıralım:

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

Yine, inputyeni satıra kadar okur ve esas olarak satırdan çıkarır. printyeni satır ekler. Böylece ikisi de girişi değiştirirken, değişiklikleri iptal edilir. (Yani aslında birbirlerinin tamamlayıcısıdırlar.)

Ve inputdosya sonu karakterini aldığında, görmezden geldiğimiz ve daha sonra programdan çıktığımız EOFError'u yükseltir.

Linux / Unix'te, kediden borulama yapabiliriz:

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

Veya dosyayı stdin'den yeniden yönlendirebiliriz:

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

Modülü komut dosyası olarak da yürütebiliriz:

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

İşte inputPython 3'teki yerleşik yardım :

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

Burada kullanarak bir demo script hazırlıyoruz sys.stdin. Dosya benzeri bir nesne üzerinde yineleme yapmanın etkili yolu, dosya benzeri nesneyi yineleyici olarak kullanmaktır. Bu girişten stdout'a yazmak için tamamlayıcı yöntem basitçe kullanmaktır sys.stdout.write:

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

Doğru göründüğünden emin olmak için tekrar yazdırın:

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

Ve girdileri dosyaya yönlendirmek:

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

Komuta girdi:

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

Golf için Dosya Tanımlayıcıları

Dosya tanımlayıcıları için yana stdinve stdout0 ve 1 sırasıyla, biz de karşı olanlar geçebilir openPython 3 (değil 2 ve not hala Stdout'a yazma için 'w' gerektiğini) 'de.

Sisteminizde bu işe yararsa, daha fazla karakter tıraş olur.

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

Python 2'ler io.opende bunu yapıyor, ancak içe aktarma çok daha fazla yer kaplıyor:

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

Diğer yorumları ve cevapları ele alma

Bir yorum ''.join(sys.stdin)golf için önermektedir , ancak bu aslında sys.stdin.read () 'den daha uzundur - artı Python bellekte fazladan bir liste oluşturmalıdır (bir liste verilmediğinde bu şekilde str.joinçalışır) - kontrast için:

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

En iyi cevap şunları önerir:

import fileinput

for line in fileinput.input():
    pass

Ancak, sys.stdinyineleyici protokolü de dahil olmak üzere dosya API'sını uyguladığından, bu sadece bununla aynıdır:

import sys

for line in sys.stdin:
    pass

Başka bir cevap bunu gösteriyor. Sadece bir tercüman bunu yaparsanız, yapmanız gerektiğini unutmayın Ctrl- dLinux ya da Mac üzerinde iseniz ya Ctrl- zWindows üzerinde (sonra Entersürecine sonu dosyaya karakterini göndermek için). Ayrıca, bu cevap print(line)- '\n'sonuna sonuna bir ekleyen - kullanımını önermektedir print(line, end='')(Python 2'de ihtiyacınız varsa from __future__ import print_function).

Asıl kullanım örneği fileinputbir dizi dosyada okumak içindir.


103

Başkaları tarafından önerilen cevap:

for line in sys.stdin:
  print line

çok basit ve pitoniktir, ancak komut satırının girdi satırlarında yinelemeye başlamadan önce EOF'a kadar bekleyeceğini belirtmek gerekir.

Bu, tail -f error_log | myscript.pysatırları beklendiği gibi işlemeyeceği anlamına gelir .

Böyle bir kullanım durumu için doğru komut dosyası şöyledir:

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

    if not line:
        break

    print line

GÜNCELLEME
Yorumlardan, python 2'de yalnızca arabellekleme olabileceği temizlendi, böylece yazdırma araması yapılmadan önce arabellek veya EOF'un dolmasını beklersiniz.


8
for line in sys.stdin:Desen değil EOF bekleyin. Ancak çok küçük dosyalar üzerinde test yaparsanız, yanıtlar arabelleğe alınabilir. Ara sonuçları okuduğunu görmek için daha fazla veriyle test edin.
mb.

Python 2.6.6 kullanırken bir akıştan girdi alırken Dosya Sonu veya arabelleğe alma için bekliyorum, ancak 3.1.3 ile yapmıyorum. Not print line3.1.3 'te uyandırmaz, fakat print(line)uyanır.
ctrl-alt-delor

python 2.7.5 "sys.stdin satırında", EOF veya makul miktarda veri arabelleğe alınana kadar engeller. Akış işleme için iyi. Satır satır işleme veya kullanıcı girişi için iyi değil.
Sean

2
Bunun libc'de tty'nin tespiti ile ilgili olduğundan şüpheleniyorum, bu yüzden interaktif bir kabukta boru tespit ettiğinde hiçbiri tespit etmiyor, tty'yi beklemiyor, ld_preload aracılığıyla bir şim enjekte ettiğine inanıyorum kullanışlı bir araç. şüpheli böyle teslim)
Mâtt Frëëman

8
@Sean: yanlış . for line in sys.stdin:"EOF'a kadar engellemez". Python 2'de karşılık gelen arabellek dolana kadar satırları geciktiren bir okuma hatası var . EOF ile ilgisi olmayan bir tamponlama sorunudur. Geçici çözüm için, kullanın for line in iter(sys.stdin.readline, ''):( io.open()normal dosyalar için kullanın ). Python 3'te buna ihtiyacınız yok.
jfs

39

Bu standart girişi standart çıkışa yansıtır:

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

31

Tüm anwers kullanarak sys.stdin, en az bir argüman varsa, bir argüman dosyasından okumak için aşağıdaki gibi bir şey yapabilir ve aksi takdirde stdin'e geri dönebilirsiniz:

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

ve ya

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

veya

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

ya da

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

Bu, Python betiğinizin cat, grepve gibi birçok GNU / Unix programı gibi davranmasını sağlar sed.


17

argparse kolay bir çözümdür

Hem Python sürüm 2 hem de 3 ile uyumlu örnek:

#!/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()

Bu komut dosyasını birçok şekilde çalıştırabilirsiniz:

1. Kullanma stdin

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

  veya değiştirerek daha kısa echotarafından burada dize :

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

2. Dosya adı bağımsız değişkenini kullanma

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

3. stdinÖzel dosya adı ile kullanma-

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

Girdi dosyası sıkıştırılmışsa, ne yapılacağına dair bir cevap: stackoverflow.com/a/33621549/778533 Biri de yapabilir add_argument('--in've daha sonra komut dosyasına bağlanabilir --in -ve komut satırına ekleyebilir . PS in, bir değişken / öznitelik için çok iyi bir isim değildir.
tommy.carstensen

insadece bir değişken için kötü bir isim değil, yasadışı. ayrılmış anahtar kelime args.in.read()nedeniyle InvalidSyntax hatasını yükseltir in. infilePython argparse belgelerinin yaptığı gibi yeniden adlandırabilir : docs.python.org/3/library/…
Ken Colton

@ Tommy.carstensen Geri bildiriminiz için teşekkür ederiz, sadece cevabı geliştirdim. Mutlu Noeller ve mutlu yıllar ;-)
olibre

14

Aşağıdaki kod çipi size yardımcı olacaktır (tüm stdin engellemenin EOFtek bir dizeye okunmasını sağlayacaktır ):

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

8

Kimse bu hack bugüne kadar bahsetmemişti oldukça şaşırdım:

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

python2'de set()aramayı bırakabilirsiniz , ancak her iki şekilde de


1
Neden readlinesbölünmüş çizgileri jointekrar kullanıyorsunuz? Sadece yazabilirsinizprint(sys.stdin.read())
musiphil

Bu, gerektiğinden daha fazla bellek kullanacaktır, çünkü python'un ekstra bir dizi oluşturması gerekir.
Harry Moreno

Aslında değil, çünkü writegeri döner Noneve ayarlanan boyut asla 1'den büyük olmaz ( =len(set([None])))
Uri Goren

7

Bunu dene:

import sys

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

ve şunlarla kontrol edin:

$ echo "Hello World" | python myFile.py


6

Şundan okuyun sys.stdin, ancak Windows'daki ikili verileri okumak için sys.stdin, metin modunda açıldığından ve bunların \r\nyerini alması bozulacağından , çok dikkatli olmanız gerekir \n.

Çözüm, Windows + Python 2 algılanırsa ve Python 3'te kullanıldığında modu ikili olarak ayarlamaktır 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

Aşağıdaki yöntemi kullanın, stdin (ben json ayrıştırma için kullanın) bir dize döndürür. Windows üzerinde pipe ve istem ile çalışır (henüz Linux'ta test edilmemiştir). İstendiğinde, iki satır sonu girişin sonunu gösterir.

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

Çözümde yaşadığım sorun

import sys

for line in sys.stdin:
    print(line)

stdin'e herhangi bir veri iletmezseniz, sonsuza kadar engeller. Bu yüzden bu yanıtı seviyorum : önce stdin hakkında bazı veriler olup olmadığını kontrol edin ve ardından okuyun. Sonunda bunu yaptım:

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)

Eğer durum olsa bile bir yöntem içine bu iğrenç gizleme tavsiye ederim.
tiktak

1
Bu yöntem programın uygulanabilirliğini ciddi şekilde sınırlar: örneğin, bunu terminalden gelen etkileşimli giriş için kullanamazsınız, çünkü selectçağrı çağrıldığında giriş neredeyse hiçbir zaman "hazır" olmaz ; veya stdin yavaş bir ortamdaki (ağ, CD, kaset vb.) bir dosyaya bağlıysa sorunlarla da karşılaşabilirsiniz. "Eğer stdin'e herhangi bir veri iletmezseniz, sonsuza kadar engeller" dediniz. bir sorun , ama bir özellik olduğunu söyleyebilirim . Çoğu CLI programı (örneğin cat) bu şekilde çalışır ve beklenir. EOF, girişin sonunu algılamak için ihtiyaç duyduğunuz tek şeydir.
musiphil

2

Bunu borulu soketleri okumak için çalışmak için alırken bazı sorunları vardı. Soket kapandığında, etkin bir döngüde boş dize döndürmeye başladı. Bu benim çözümüm (sadece linux'da test ettim, ancak umarım diğer tüm sistemlerde çalışır)

import sys, os
sep=os.linesep

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

Dolayısıyla, bir soketi dinlemeye başlarsanız, düzgün çalışır (örneğin bash'da):

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

Telnet ile arayabilir veya bir tarayıcıyı localhost'a yönlendirebilirsiniz: 12345


1

Bununla ilgili olarak:

for line in sys.stdin:

Sadece çok büyük bir dosya için python 2.7'de (başkasının önerisini izleyerek) denedim ve tam olarak yukarıda belirtilen nedenlerle (hiçbir şey uzun süre olmaz) önermiyorum.

Biraz daha pythonic bir çözüm buldum (ve daha büyük dosyalarda çalışır):

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

Sonra betiği yerel olarak çalıştırabilirim:

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

Sorunun sorduğu gibi, bir dosyayı açmak stdin'den okuma yapmıyor. -1
Aaron Hall

Bu durumda sys.stdin, komut dosyasına bir komut satırı argümanı olarak geçiyorum .
szeitlin

1
sys.stdinKomut dosyasına bir komut satırı argümanı olarak nasıl geçebilirsiniz ? Bağımsız değişkenler dizelerdir ve akışlar dosya benzeri nesnelerdir, aynı değildirler.
DeFazer

@DeFazer nasıl kullanılacağını göstermek için düzenlenmiştir. Bağımsız değişkenler dizelerdir, evet, ancak python belgeleri ve yukarıda daha önceki bir yorumda bahsettiğim gibi, sys.stdindosya benzeri bir nesne
szeitlin

1

İçin Python 3 olacağını:

# Filename e.g. cat.py
import sys

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

Bu temelde basit bir kedi şeklidir (1), çünkü her satırdan sonra yeni satır eklemez. Bunu kullanabilirsiniz (Dosyayı yürütülebilir chmod +x cat.pygibi işaretledikten sonra, örneğin:

echo Hello | ./cat.py

0

os.read(0, x) Stdin'i temsil eden 0'dan xbayt okuyan vardır . Bu, arabelleksiz bir okuma, sys.stdin.read ()


0

-cKomut kullanırken , zor bir yol olarak, stdin(ve bazı durumlarda daha esnek) okumak yerine , satma komutunu işaretle başlayan bir parantez içinde tırnak içine alarak bir kabuk komut dosyası komutunu da python komutunuza iletebilirsiniz $.

Örneğin

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

Bu, goldendict'in geçmiş dosyasındaki satır sayısını sayar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.