How do you read from stdin?

Я пытаюсь решить некоторые проблемы с гольф-кодом, но все они требуют от stdin, Как мне получить это в Python?

26 ответов

Вы могли бы использовать 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.

Вы, вероятно, найдете эту статью Wikibook о вводе / выводе в Python также полезной ссылкой.

import sys

for line in sys.stdin:
    print line

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?

Я пытаюсь решить некоторые проблемы с гольфом, но все они требуют ввода от stdin. Как мне получить это в Python?

Ты можешь использовать:

  • sys.stdin - Файловый объект - вызов sys.stdin.read() читать все
  • input(prompt) - передать ему необязательный запрос на вывод, он читает от стандартного ввода до первой новой строки, которую он удаляет. Вам придется делать это несколько раз, чтобы получить больше строк, в конце ввода это вызывает EOFError. (Вероятно, не подходит для игры в гольф.) В Python 2 это rawinput(prompt),
  • open(0).read() - в Python 3 open принимает файловые дескрипторы (целые числа, представляющие ресурсы ввода-вывода операционной системы), а 0 - дескриптор stdin, Возвращает объект типа файла sys.stdin - вероятно, ваш лучший выбор для игры в гольф.
  • open('/dev/stdin').read() - похожий на open(0), работает на Python 2 и 3, но не на Windows (или даже Cygwin).
  • fileinput.input() - возвращает итератор над строками во всех файлах, перечисленных в sys.argv[1:] или стандартный ввод, если не дано. Используйте как ''.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

пример файла

Скажем, у вас есть файл, 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) для чтения из 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 из 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 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() - плюс 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' до конца - использовать print(line, end='') вместо этого (если в Python 2 вам понадобится from __future__ import print_function).

Реальный вариант использования для fileinput для чтения в серии файлов.

Ответ, предложенный другими:

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 перед вызовом печати.

Это отобразит стандартный ввод в стандартный вывод:

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

Опираясь на все ответы, используя 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, grep а также sed,

В дополнение к этим ответам вы также можете использовать argparse это также обратно совместимо с python2.7. Пример совместим как с python2, так и с python3:

#!/usr/bin/python

import argparse
import sys

parser = argparse.ArgumentParser()
parser.add_argument('in', default=sys.stdin, type=argparse.FileType('r'), nargs='?')
args = parser.parse_args()

data = args.in.read()

Вы можете запустить этот скрипт двумя способами:

  • С помощью stdin:

     echo 'foo bar' | ./above-script.py
    
  • Используя аргумент имени файла:

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

Следующий фрагмент кода поможет вам (он будет читать все блокирование stdin в EOFв одну строку):

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

Я очень удивлен, что никто не упомянул этот хак до сих пор:

python -c "import sys;print (''.join([l for l in sys.stdin.readlines()]))"

совместим как с python2, так и с python3

Я использую следующий метод, он возвращает строку из 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

Вы можете читать из stdin и затем сохранять входные данные в "data" следующим образом:

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

Читать из 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()

Попробуй это:

import sys

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

и проверьте это с:

$ echo "Hello World" | python myFile.py

Начиная с Python 3.8 вы можете использовать выражение присваивания :

      while (line := input()):
    print(line)

Для 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)

в том, что если вы не передадите данные в 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)

Когда используешь -c как хитрый способ вместо того, чтобы читать stdin (и более гибко в некоторых случаях), вы также можете передать команду сценария оболочки своей команде python, поместив команду оболочки в кавычки в круглых скобках, начиная с $ знак.

например

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

Это посчитает количество строк из файла истории goldendict.

В соответствии с этим:

for line in sys.stdin:

Я только что попробовал это на python 2.7 (следуя чьему-либо предложению) для очень большого файла, и я не рекомендую его именно по причинам, указанным выше (в течение долгого времени ничего не происходит).

Я получил немного более питонное решение (и оно работает с большими файлами):

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

У меня были некоторые проблемы при получении этого для работы через сокеты, переданные по каналу. Когда сокет закрылся, он начал возвращать пустую строку в активном цикле. Так что это мое решение (которое я тестировал только в 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

Стоит сказать о короткой цепочке командной строкиinputпредпочтительнееfileinputиsys.stdinпоскольку он не требует импорта и короче для ввода.

      $ echo hello word | python3 -c "print(input().upper())"
HELLO WORD
Неблокирующий, байтовый режим, стандартный ввод -> стандартный вывод:
      # pipe.py

import os, sys, time

os.set_blocking(0, False)
sys.stdin = os.fdopen(0, 'rb', 0)
sys.stdout = os.fdopen(1, 'wb', 0)

while 1:
    time.sleep(.1)
    try: out = sys.stdin.read()
    except:
        sys.stdout.write(b"E")
        continue
    if out is None:
        sys.stdout.write(b"N")
        continue
    if not out:
        sys.stdout.write(b"_")
        break
    # working..
    out = b"<" + out + b">"
    sys.stdout.write(out)

sys.stdout.write(b".\n")
Использование:
      $ for i in 1 2 3; do sleep 1; printf "===$i==="; done | python3 pipe.py
NNNNNNNNN<===1===>NNNNNNNNN<===2===>NNNNNNNNN<===3===>_.
Минимальный код:
      import os, sys

os.set_blocking(0, False)
fd0 = os.fdopen(0, 'rb', 0)
fd1 = os.fdopen(1, 'wb', 0)

while 1:
    bl = fd0.read()
    if bl is None: continue
    if not bl: break
    fd1.write(bl)

Протестировано на Linux, Python 3.9.2

Есть os.read(0, x)который читает xbytes от 0, который представляет стандартный ввод. Это небуферизованное чтение, более низкий уровень, чем sys.stdin.read()

n = int(raw_input())
for i in xrange(n):
    name, number = raw_input().split()
Другие вопросы по тегам