Как вы читаете из стандартного ввода?

avatar
tehryan
20 сентября 2009 в 05:48
1854768
23
1590

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

Источник

Ответы (23)

avatar
hant0508
19 ноября 2021 в 00:10
1

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

while (line := input()):
    print(line)
avatar
u0b34a0f6ae
1 февраля 2021 в 08:01
1024

Вы можете использовать модуль fileinput:

import fileinput

for line in fileinput.input():
    pass

fileinput будет перебирать все строки ввода, указанные как имена файлов, указанные в аргументах командной строки, или стандартный ввод, если аргументы не указаны.

Примечание: line будет содержать завершающую новую строку; чтобы удалить его, используйте line.rstrip()

Amir reza Riahi
21 марта 2021 в 10:51
0

какая разница между input() и fileinput.input()?

Boris
8 апреля 2021 в 15:14
2

@AmirrezaRiahi input() считывает одну строку из стандартного ввода, тогда как fileinput.input() будет перебирать все строки ввода, указанные как имена файлов, указанные в аргументах командной строки, или стандартный ввод, если аргументы не указаны при условии

avatar
Bouni
11 ноября 2019 в 07:19
5

Я использую следующий метод, он возвращает строку из 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
avatar
kasravnd
30 июня 2019 в 01:54
1

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

например,

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

Будет подсчитано количество строк из файла истории goldendict.

catleeball
29 июля 2020 в 23:33
1

Это умно, я подключался к python -c таким образом, и это был интересный обходной путь. Спасибо, что поделились. :)

avatar
AdamKalisz
4 мая 2019 в 18:23
4

Для 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
avatar
Jay
15 апреля 2019 в 17:29
0

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

avatar
oHo
27 сентября 2018 в 13:40
18

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 -
tommy.carstensen
4 декабря 2018 в 13:59
0

Вот ответ о том, что делать, если входной файл сжат: coderhelper.com/a/33621549/778533 Можно также сделать add_argument('--in', а затем передать скрипту по конвейеру и добавить --in - в командную строку. P.S. in - не очень хорошее имя для переменной / атрибута.

Ken Colton
23 декабря 2018 в 21:52
0

in - это не просто плохое имя для переменной, это незаконно. args.in.read() вызовет ошибку InvalidSyntax из-за зарезервированного ключевого слова in. Можно просто переименовать в infile, как это делают документы python argparse: docs.python.org/3/library/…

oHo
27 декабря 2018 в 21:20
0

Спасибо @ tommy.carstensen за ваш отзыв, я только что улучшил ответ. Веселого Рождества и счастливого Нового года ;-)

avatar
Eugene Yokota
10 декабря 2017 в 19:22
226

Вот из Изучение 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.
jfs
16 ноября 2012 в 04:32
4

Вот более эффективный (и, возможно, более быстрый) способ подсчета строк в Python: print(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), ''))). см. wc-l.py

istepaniuk
17 ноября 2015 в 11:14
12

Использование cat здесь излишне. Правильный вызов для систем Unix - python countlines.py < countlines.py.

Aaron Hall♦
1 августа 2016 в 14:56
16

«Изучение Python» неверно, когда побуждает пользователей использовать readlines(). Файловые объекты предназначены для итерации без материализации всех данных в памяти.

GeePokey
18 мая 2021 в 21:55
0

@istepaniuk Что касается "использования cat", я считаю, что использование cat filespec | filters в целом более удобно, когда я настраиваю параметры командной строки для фильтров, поскольку они каждый раз будут в конце строки.

avatar
Tomas Tomecek
2 ноября 2017 в 08:49
4

У меня проблема с решением

import sys

for line in sys.stdin:
    print(line)

заключается в том, что если вы не передадите какие-либо данные на стандартный ввод, он будет заблокирован навсегда. Вот почему мне нравится этот ответ: сначала проверьте, есть ли данные о 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
4 ноября 2017 в 01:41
0

Я бы серьезно рекомендовал скрыть это ужасное условие в методе.

musiphil
27 февраля 2019 в 18:20
1

Этот метод серьезно ограничивает применимость программы: например, вы не можете использовать его для интерактивного ввода с терминала, потому что ввод почти никогда не будет "готов" при вызове select; или вы также можете столкнуться с проблемами, если stdin подключен к файлу на медленном носителе (сеть, компакт-диск, лента и т. д.). Вы сказали, что «если вы не передадите никаких данных на стандартный ввод, он будет заблокирован навсегда». это проблема , но я бы сказал, что это функция . Большинство программ CLI (например, cat) работают именно так, и от них ожидается. EOF - единственное, от чего вы должны зависеть, чтобы определить конец ввода.

avatar
Uri Goren
7 ноября 2016 в 10:08
10

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

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

в python2 вы можете отбросить вызов set(), но в любом случае это будет слово

musiphil
27 февраля 2019 в 18:28
1

Зачем использовать readlines, который разбивается на строки, а затем снова join? Вы можете просто написать print(sys.stdin.read())

Harry Moreno
17 апреля 2020 в 06:46
0

Это будет использовать больше памяти, чем необходимо, потому что python должен создать дополнительный массив.

Uri Goren
27 мая 2020 в 07:24
0

Ну, не совсем, потому что write возвращает None, а размер набора никогда не будет больше 1 (=len(set([None])))

avatar
anatoly techtonik
14 августа 2016 в 05:12
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()
avatar
Aaron Hall
30 июля 2016 в 04:10
156

Как вы читаете из стандартного ввода в Python?

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

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

  • sys.stdin - объект в виде файла - вызовите sys.stdin.read(), чтобы прочитать все.
  • input(prompt) - передать ему необязательное приглашение для вывода, он читает от стандартного ввода до первого символа новой строки, который он удаляет. Вам придется делать это несколько раз, чтобы получить больше строк, в конце ввода возникает EOFError. (Вероятно, не очень подходит для игры в гольф.) В Python 2 это rawinput(prompt).
  • open(0).read() - В Python 3 встроенная функция open принимает файловые дескрипторы (целые числа, представляющие ресурсы ввода-вывода операционной системы), а 0 - дескриптор stdin. Он возвращает объект в виде файла, например sys.stdin - вероятно, ваш лучший выбор для игры в гольф. В Python 2 это io.open.
  • 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, например, если вы перенаправляете данные на стандартный ввод:

$ 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 в 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

Или мы можем просто перенаправить файл со стандартного ввода:

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

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

avatar
szeitlin
8 июня 2016 в 23:02
2

В отношении этого:

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
Aaron Hall♦
1 августа 2016 в 13:27
0

Открытие файла - это не чтение из stdin, как задается вопрос. -1

szeitlin
1 августа 2016 в 22:56
0

В этом случае я передаю sys.stdin в качестве аргумента командной строки сценарию.

DeFazer
17 сентября 2016 в 02:12
1

Как передать скрипту sys.stdin в качестве аргумента командной строки? Аргументы - это строки, а потоки - это файловые объекты, это не одно и то же.

szeitlin
17 сентября 2016 в 09:37
0

@DeFazer отредактировал, чтобы показать, как его использовать. Аргументы - это строки, да, но, как я упоминал в документах python и в предыдущем комментарии выше, sys.stdin является файловым объектом.

avatar
Chandan Kumar
25 января 2016 в 10:26
14

Следующая микросхема кода поможет вам (она прочитает всю блокировку stdin до EOF, в одну строку):

import sys
input_str = sys.stdin.read()
print input_str.split()
avatar
estani
29 октября 2014 в 14:57
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

avatar
Wei
20 июля 2014 в 21:33
7

Вы можете читать из стандартного ввода, а затем сохранять входные данные в «данные» следующим образом:

data = ""
for line in sys.stdin:
    data += line
musiphil
27 февраля 2019 в 18:31
0

То же самое можно сделать с помощью data = sys.stdin.read() без проблемы повторяющихся конкатенаций строк.

avatar
Bouba
27 августа 2013 в 15:43
7

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

import sys

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

и проверьте это с помощью:

$ echo "Hello World" | python myFile.py
avatar
Emil Lundberg
29 июля 2013 в 15:04
32

Основываясь на всех ответах с использованием sys.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.

avatar
rlib
9 августа 2012 в 16:31
39

Это будет отображать стандартный ввод на стандартный вывод:

import sys
line = sys.stdin.readline()
while line:
    print line,
    line = sys.stdin.readline()
avatar
Massimiliano Torromeo
30 сентября 2011 в 09:08
105

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

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

mb.
11 июля 2012 в 02:06
9

Шаблон for line in sys.stdin: не ожидает EOF. Но если вы тестируете очень маленькие файлы, ответы могут буферизоваться. Протестируйте с большим количеством данных, чтобы увидеть, что он считывает промежуточные результаты.

ctrl-alt-delor
7 сентября 2012 в 09:41
0

Я жду окончания файла или буферизации при вводе данных из потока при использовании python 2.6.6, но с 3.1.3 я этого не делаю. Примечание print line не просыпается в 3.1.3, но print(line) делает.

Sean
15 октября 2013 в 11:34
0

мой python 2.7.5 "для строки в sys.stdin", блоки до EOF или некоторого разумного количества данных буферизированы. Штраф за потоковую обработку. Не подходит для построчной обработки или пользовательского ввода.

Mâtt Frëëman
12 марта 2015 в 08:16
2

Я подозреваю, что это связано с обнаружением tty в libc, поэтому, когда вы обнаруживаете tty в интерактивной оболочке, он не обнаруживает tty, unbuffer из expect-dev - удобная утилита, которая, как я считаю, вводит прокладку через ld_preload, поэтому is_atty возвращает true (я подозреваю, вот как он это вручает)

jfs
23 января 2016 в 07:46
0

@MattFreeman: в данном случае это не связано с «строчной или блочной буферизацией в зависимости от того, является ли stdout tty». Ошибка упреждающего чтения в Python 2 задерживает ввод, даже если tail должен был вовремя сбросить свой вывод. for line in sys.stdin отлично работает на Python 3.

musiphil
27 февраля 2019 в 18:35
0

В любом случае for line in sys.stdin: не предназначен для действительно интерактивного ввода (например, получение ввода с терминала после подсказок). В большинстве случаев вам не нужно заботиться о том, буферизован ли ввод или нет.

avatar
Pat Notz
3 марта 2011 в 19:05
252

Python также имеет встроенные функции input() и raw_input(). См. Документацию Python в разделе Встроенные функции.

Например,

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

или

name = input("Enter your name: ")   # Python 3
tripleee
22 декабря 2015 в 08:51
8

Это считывает одну строку, что на самом деле не то, о чем спрашивал OP. Я интерпретирую вопрос как «как мне прочитать кучу строк от дескриптора открытого файла до EOF?»

chrisfs
22 апреля 2018 в 21:45
4

OP не просит читать ввод с клавиатуры, он просит читать из стандартного ввода, который в ситуации конкурса обычно предоставляется участникам.

clockw0rk
16 июля 2019 в 13:44
2

это то, что мне было нужно, Google привел меня сюда. интересно, мне удалось закодировать теги rfid, datetime, базы данных, но никогда не удосужился прочитать ввод от пользователя lol

avatar
user303110
20 июля 2010 в 10:30
520
import sys

for line in sys.stdin:
    print(line)

Обратите внимание, что в конце будет символ новой строки. Чтобы удалить новую строку в конце, используйте line.rstrip(), как сказал @brittohalloran.

avp
1 ноября 2018 в 21:22
12

line.rstrip ('\ n'), иначе будут удалены все пробелы

addicted
18 декабря 2018 в 07:28
0

используя этот метод, как мы узнаем, когда заканчивается входной поток? Я хочу добавить запятую после каждой строки , за исключением для последней строки.

Diego Queiroz
20 января 2019 в 20:39
0

Я получаю: TypeError: объект FileWrapper не повторяется.

josch
9 июля 2019 в 08:22
1

@avp это не будет правильно обрабатывать окончания строк \r\n

ks1322
4 апреля 2021 в 13:24
0

Другой способ удалить лишнюю новую строку в конце - использовать print(line, end='').

avatar
Mark Rushakoff
20 сентября 2009 в 05:53
769

Есть несколько способов сделать это.

Вы, вероятно, найдете эту статью Wikibook о вводе-выводе в Python как полезную справочную информацию.

bobsbeenjamin
9 декабря 2020 в 01:34
0

Третий вариант - это то, что я искал для обработки ввода на code.golf.