คุณอ่านจาก stdin อย่างไร


1470

ฉันพยายามที่จะทำบางส่วนของรหัสกอล์ฟท้าทาย stdinแต่พวกเขาทั้งหมดต้องมีการป้อนข้อมูลที่จะนำมาจาก ฉันจะได้รับสิ่งนั้นใน Python ได้อย่างไร

คำตอบ:


950

คุณสามารถใช้fileinputโมดูล:

import fileinput

for line in fileinput.input():
    pass

fileinput จะวนซ้ำทุกบรรทัดในอินพุตที่ระบุเป็นชื่อไฟล์ที่กำหนดในอาร์กิวเมนต์บรรทัดคำสั่งหรืออินพุตมาตรฐานหากไม่มีการระบุอาร์กิวเมนต์

หมายเหตุ: lineจะมีบรรทัดใหม่ต่อท้าย; เพื่อลบมันใช้line.rstrip()


1
@ BorislavStoilov และคำตอบนี้ตอบคำถามได้อย่างถูกต้อง: "หรืออินพุตมาตรฐานหากไม่มีข้อโต้แย้งใด ๆ "
Dietmar

1
เอกสารระบุว่ามันตรงข้ามกับ stdin: "นี่ทำซ้ำข้ามบรรทัดของไฟล์ทั้งหมดที่แสดงรายการใน sys.argv [1:], เริ่มต้นที่ sys.stdin หากรายการว่างถ้าชื่อไฟล์เป็น '-' ก็จะถูกแทนที่ด้วย โดย sys.stdin เมื่อต้องการระบุรายการทางเลือกของชื่อไฟล์ให้ส่งเป็นอาร์กิวเมนต์แรกของอินพุต () นอกจากนี้ยังอนุญาตให้ใช้ชื่อไฟล์เดียวได้ "
Arlo

721

มีสองสามวิธีที่จะทำ

  • sys.stdinเป็นวัตถุที่คล้ายกับไฟล์ที่คุณสามารถเรียกใช้ฟังก์ชั่นreadหรือreadlinesถ้าคุณต้องการอ่านทุกอย่างหรือคุณต้องการที่จะอ่านทุกอย่างและแยกมันโดยขึ้นบรรทัดใหม่โดยอัตโนมัติ (คุณจำเป็นต้องให้import sysสิ่งนี้ทำงานได้)

  • หากคุณต้องการให้ผู้ใช้ป้อนข้อมูลคุณสามารถใช้raw_inputใน Python 2.X และinputใน Python 3

  • หากคุณเพียงต้องการอ่านตัวเลือกบรรทัดคำสั่งคุณสามารถเข้าถึงได้จากรายการsys.argv

คุณอาจพบบทความ Wikibook นี้ใน I / O ใน Pythonเพื่อเป็นข้อมูลอ้างอิงที่มีประโยชน์เช่นกัน


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

งูใหญ่ยังได้สร้างฟังก์ชั่นและinput() raw_input()ดูเอกสารประกอบของ Python ในฟังก์ชั่นในตัว

ตัวอย่างเช่น,

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

หรือ

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

7
นี่เป็นการอ่านบรรทัดเดียวซึ่งไม่ใช่สิ่งที่ OP ต้องการ ฉันตีความคำถามว่า "ฉันจะอ่านกลุ่มบรรทัดจากตัวจัดการไฟล์ที่เปิดอยู่จนถึง EOF ได้อย่างไร"
tripleee

4
OP ไม่ได้ขอให้อ่านข้อมูลจากแป้นพิมพ์เขาขอให้อ่านจาก stdin ซึ่งในสถานการณ์การแข่งขันมักจะให้แก่ผู้แข่งขัน
chrisfs

นี่คือสิ่งที่ฉันต้องการ google นำมาให้ฉันที่นี่ น่าสนใจฉันจัดการรหัสแท็ก rfid, datetime, ฐานข้อมูล แต่ไม่เคยใส่ใจที่จะอ่านข้อมูลจากผู้ใช้ lol
clockw0rk

204

มาจากLearning 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
นี่คือความทรงจำที่มีประสิทธิภาพมากขึ้น (และอาจจะเร็วกว่า) 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
"การเรียนรู้งูใหญ่" readlines()เป็นสิ่งที่ผิดในการกำกับให้ผู้ใช้สามารถใช้งาน วัตถุไฟล์มีจุดมุ่งหมายเพื่อทำซ้ำโดยไม่ทำให้ข้อมูลทั้งหมดในหน่วยความจำเป็นจริง
Aaron Hall

118

คุณอ่านจาก stdin ใน Python อย่างไร

ฉันพยายามที่จะทำสิ่งที่ท้าทายรหัสกอล์ฟ แต่พวกเขาทั้งหมดต้องป้อนข้อมูลที่จะนำมาจาก stdin ฉันจะได้รับสิ่งนั้นใน Python ได้อย่างไร

คุณสามารถใช้ได้:

  • sys.stdin- วัตถุเหมือนไฟล์ - โทรsys.stdin.read()เพื่ออ่านทุกอย่าง
  • input(prompt)- ผ่านมันพร้อมท์ให้เลือกเพื่อส่งออกมันอ่านจาก stdin ถึงขึ้นบรรทัดใหม่ครั้งแรกซึ่งมันแถบ คุณต้องทำเช่นนี้ซ้ำ ๆ เพื่อให้ได้บรรทัดมากขึ้นในตอนท้ายของอินพุตมันจะเพิ่ม EOFError (อาจจะไม่ดีสำหรับการเล่นกอล์ฟ.) ในหลาม 2 rawinput(prompt)นี้เป็น
  • open(0).read()- ในหลาม 3 ฟังก์ชั่นในตัวopenยอมรับอธิบายไฟล์ (จำนวนเต็มเป็นตัวแทนของระบบปฏิบัติการทรัพยากร IO) และ 0 stdinเป็นตัวบ่งชี้ของ มันส่งคืนวัตถุที่คล้ายไฟล์อย่างเช่นsys.stdinอาจเป็นทางออกที่ดีที่สุดสำหรับการเล่นกอล์ฟของคุณ ในหลาม 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จากsys.stdinตัวอย่างเช่นถ้าคุณข้อมูลท่อ 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ในหลาม 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.

ฟังก์ชัน Builtin input( raw_inputใน Python 2)

ฟังก์ชั่นในตัวinputอ่านจากอินพุตมาตรฐานขึ้นไปขึ้นบรรทัดใหม่ซึ่งเป็นปล้น (เมี่ยงprintซึ่งจะเพิ่มขึ้นบรรทัดใหม่โดยค่าเริ่มต้น.) นี้เกิดขึ้นจนกว่าจะได้รับ EOF (จุดสิ้นสุดของแฟ้ม) EOFErrorจุดที่มันจะเพิ่ม

ดังนั้นนี่คือวิธีที่คุณสามารถใช้inputใน Python 3 (หรือraw_inputใน Python 2) เพื่ออ่านจาก stdin ดังนั้นเราจึงสร้างโมดูล Python ที่เราเรียกว่า stdindemo.py:

$ 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

หรือเราสามารถเปลี่ยนเส้นทางไฟล์จาก stdin:

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

นอกจากนี้เรายังสามารถรันโมดูลเป็นสคริปต์:

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

นี่คือความช่วยเหลือinputจากbuiltin จาก 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ที่นี่เราทำสคริปต์การสาธิตการใช้ วิธีที่มีประสิทธิภาพในการวนซ้ำวัตถุที่มีลักษณะคล้ายไฟล์คือการใช้วัตถุที่มีลักษณะคล้ายไฟล์เป็นตัววนซ้ำ วิธีการเสริมในการเขียนไปยัง 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

Golfed เป็นคำสั่ง:

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

ตัวอธิบายไฟล์สำหรับการเล่นกอล์ฟ

เนื่องจาก file descriptors สำหรับstdinและstdoutเป็น 0 และ 1 ตามลำดับเราสามารถส่งต่อไปยังopenใน Python 3 (ไม่ใช่ 2 และโปรดทราบว่าเรายังต้องการ 'w' สำหรับการเขียนไปยัง stdout)

หากสิ่งนี้ใช้ได้กับระบบของคุณมันจะกำจัดอักขระจำนวนมาก

$ 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

การพูดถึงความคิดเห็นและคำตอบอื่น ๆ

ความคิดเห็นหนึ่งแสดงให้เห็น''.join(sys.stdin)สำหรับการเล่นกอล์ฟ แต่ที่จริงนานกว่า sys.stdin.read () - บวกหลามต้องสร้างรายการพิเศษในหน่วยความจำ (นั่นเป็นวิธีที่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)- ซึ่งเพิ่ม a '\n'ถึงท้าย - ใช้print(line, end='')แทน (ถ้าใน Python 2 คุณจะต้องใช้from __future__ import print_function)

กรณีการใช้งานจริงสำหรับใช้fileinputสำหรับอ่านในชุดไฟล์


103

คำตอบที่เสนอโดยคนอื่น ๆ :

for line in sys.stdin:
  print line

เรียบง่ายและไพเราะ แต่ต้องสังเกตว่าสคริปต์จะรอจนกว่า 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 ก่อนที่จะมีการเรียกใช้การพิมพ์


8
for line in sys.stdin:รูปแบบไม่รอ EOF แต่ถ้าคุณทดสอบไฟล์ที่มีขนาดเล็กมากการตอบสนองอาจถูกบัฟเฟอร์ ทดสอบกับข้อมูลเพิ่มเติมเพื่อดูว่ามันอ่านผลลัพธ์ระดับกลาง
mb

ฉันรอ End Of File หรือ buffering เมื่อรับอินพุตจากสตรีมเมื่อใช้ python 2.6.6 แต่ด้วย 3.1.3 ฉันไม่ หมายเหตุprint lineไม่ได้ปลุกใน 3.1.3 แต่print(line)ทำ
ctrl-alt-delor

python ของฉัน 2.7.5 "สำหรับบรรทัดใน sys.stdin" บล็อกจนถึง EOF หรือบางส่วนของข้อมูลที่เหมาะสมได้ถูกบัฟเฟอร์ ใช้ได้ดีสำหรับการประมวลผลแบบสตรีม ไม่เหมาะสำหรับการประมวลผลรายบรรทัดหรืออินพุตของผู้ใช้
ฌอน

2
ฉันสงสัยว่าสิ่งนี้เกี่ยวข้องกับการตรวจจับ tty ใน libc ดังนั้นเมื่อคุณทำการตรวจจับบนเชลล์แบบโต้ตอบมันจะตรวจจับไม่มี tty unbuffer จาก expect-dev เป็นประโยชน์ที่ฉันเชื่อว่าจะใช้ shim ผ่าน ld_preload ดังนั้น is_atty จึงคืนจริง สงสัยว่ามันเป็นวิธีการส่ง)
MâttFrëëman

8
@Sean: ผิด for line in sys.stdin:ไม่ "บล็อกจนถึง EOF" มีบั๊กแบบ read-ahead ใน 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

อาคาร anwers ทั้งหมดที่ใช้sys.stdinนอกจากนี้คุณยังสามารถทำบางสิ่งบางอย่างเช่นต่อไปนี้จะอ่านจากไฟล์อาร์กิวเมนต์ถ้าอย่างน้อยหนึ่งอาร์กิวเมนต์อยู่และถอยกลับไปเป็นอย่างอื่น 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, และgrepsed


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/778533คุณสามารถทำได้add_argument('--in'จากนั้นไพพ์ไปยังสคริปต์และเพิ่มลง--in -ในบรรทัดคำสั่ง PS inไม่ใช่ชื่อที่ดีมากสำหรับตัวแปร / คุณสมบัติ
tommy.carstensen

inไม่ใช่แค่ชื่อที่ไม่ดีสำหรับตัวแปร แต่มันผิดกฎหมาย args.in.read()จะเพิ่มข้อผิดพลาดของ InvalidSyntax เนื่องจากinคำสำคัญที่สงวนไว้ สามารถเปลี่ยนชื่อให้infileชอบเอกสาร python argparse ได้ที่: docs.python.org/3/library/…
Ken Colton

ขอบคุณ @ tommy.carstensen สำหรับความคิดเห็นของคุณฉันเพิ่งปรับปรุงคำตอบ สุขสันต์วันคริสต์มาสและสวัสดีปีใหม่ ;-)
olibre

14

ชิปของรหัสต่อไปนี้จะช่วยคุณได้ (มันจะอ่าน stdin ทั้งหมดที่บล็อกEOFเป็นหนึ่งสาย):

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())
musiphil

สิ่งนี้จะใช้หน่วยความจำมากกว่าที่จำเป็นเนื่องจากไพ ธ อนต้องการสร้างอาร์เรย์เพิ่มเติม
Harry Moreno

ไม่เลยเพราะ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"ดังต่อไปนี้:

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


สิ่งเดียวกันสามารถทำได้data = sys.stdin.read()โดยไม่มีปัญหาของการต่อสตริงซ้ำ
Musiphil

6

อ่านจากsys.stdinแต่เพื่ออ่านข้อมูลไบนารีใน Windowsคุณจะต้องระมัดระวังเป็นพิเศษเพราะsys.stdinมีการเปิดในโหมดข้อความและมันจะเสียหายแทนที่พวกเขาด้วย\r\n\n

การแก้ปัญหาคือโหมดตั้งค่าไบนารีหาก Windows + งูหลาม 2 มีการตรวจพบและงูหลาม 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) เมื่อพร้อมต์การขึ้นบรรทัดใหม่สองบรรทัดจะเป็นการระบุจุดสิ้นสุดของอินพุต

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)

ฉันขอแนะนำอย่างจริงจังให้ซ่อนความน่ากลัวนี้หากเงื่อนไขเป็นวิธีการ
tiktak

1
วิธีนี้ จำกัด การบังคับใช้ของโปรแกรมอย่างจริงจัง: ตัวอย่างเช่นคุณไม่สามารถใช้สิ่งนี้สำหรับการป้อนข้อมูลเชิงโต้ตอบจากเทอร์มินัลเนื่องจากอินพุตจะไม่เคย "พร้อม" เมื่อselectถูกเรียก หรือคุณอาจประสบปัญหาหาก stdin เชื่อมต่อกับไฟล์บนสื่อที่ช้า (เครือข่ายซีดีเทป ฯลฯ ) คุณบอกว่า "ถ้าคุณไม่ส่งข้อมูลใด ๆ ไปยัง stdin มันจะปิดกั้นตลอดไป" เป็นปัญหาแต่ผมจะบอกว่ามันเป็นคุณลักษณะ โปรแกรม CLI ส่วนใหญ่ (เช่นcat) ทำงานในลักษณะนี้และคาดว่าจะ EOF เป็นสิ่งเดียวที่คุณควรขึ้นอยู่กับการตรวจจับจุดสิ้นสุดของอินพุต
musiphil

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 (ทำตามคำแนะนำของคนอื่น) สำหรับไฟล์ที่มีขนาดใหญ่มากและฉันไม่แนะนำเพราะเหตุผลดังกล่าวข้างต้น (ไม่มีอะไรเกิดขึ้นเป็นเวลานาน)

ฉันสิ้นสุดด้วยโซลูชัน 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

การเปิดไฟล์ไม่ได้อ่านจาก stdin เช่นคำถามที่ถาม -1
Aaron Hall

ในกรณีนี้ฉันผ่านsys.stdinเป็นอาร์กิวเมนต์บรรทัดคำสั่งไปยังสคริปต์
szeitlin

1
คุณจะส่งผ่านsys.stdinอาร์กิวเมนต์บรรทัดคำสั่งไปยังสคริปต์ได้อย่างไร อาร์กิวเมนต์เป็นสตริงและสตรีมเป็นวัตถุที่มีลักษณะคล้ายไฟล์ แต่จะไม่เหมือนกัน
DeFazer

@DeFazer แก้ไขเพื่อแสดงวิธีการใช้งาน ข้อโต้แย้งคือสตริงใช่ แต่ในฐานะที่เป็นเอกสารหลามและฉันพูดถึงในความคิดเห็นก่อนหน้านี้ข้างต้นsys.stdinเป็นวัตถุเหมือนไฟล์
szeitlin

1

สำหรับPython 3 :

# Filename e.g. cat.py
import sys

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

นี่เป็นรูปแบบง่ายๆของแมว (1) เนื่องจากมันไม่ได้เพิ่มบรรทัดใหม่หลังจากแต่ละบรรทัด คุณสามารถใช้สิ่งนี้ได้ (หลังจากที่คุณทำเครื่องหมายไฟล์ที่สามารถใช้งานได้chmod +x cat.pyเช่น:

echo Hello | ./cat.py

0

มี os.read(0, x) ที่อ่าน xbytes จาก 0 ซึ่งหมายถึง stdin นี่คือการอ่านแบบไม่มีบัฟเฟอร์ระดับต่ำกว่า sys.stdin.read ()


0

เมื่อใช้-cคำสั่งเป็นวิธีที่ยุ่งยากแทนการอ่านstdin(และมีความยืดหยุ่นมากกว่าในบางกรณี) คุณสามารถส่งคำสั่งเชลล์สคริปต์ได้เช่นกันไปยังคำสั่ง python ของคุณโดยใส่คำสั่ง sell ในเครื่องหมายคำพูดในวงเล็บที่เริ่มต้นด้วย$เครื่องหมาย

เช่น

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.