Odpowiedzi:
Możesz użyć fileinput
modułu:
import fileinput
for line in fileinput.input():
pass
fileinput
przejdzie przez wszystkie linie na wejściu określone jako nazwy plików podane w argumentach wiersza poleceń lub standardowe wejście, jeśli nie podano argumentów.
Uwaga: line
będzie zawierać znak nowej linii; aby go usunąć użyjline.rstrip()
Można to zrobić na kilka sposobów.
sys.stdin
jest obiektem podobnym do pliku, do którego możesz wywoływać funkcje read
lub readlines
jeśli chcesz wszystko przeczytać lub chcesz wszystko przeczytać i automatycznie podzielić je na nową linię . (Musisz import sys
to zrobić, aby zadziałało).
Jeśli chcesz, aby skłonić użytkownika do wejścia, można użyć raw_input
w Pythonie 2.x i tylko input
w Pythonie 3.
Jeśli chcesz po prostu przeczytać opcje wiersza polecenia, możesz uzyskać do nich dostęp za pośrednictwem listy sys.argv .
Prawdopodobnie okaże się ten artykuł na Wikibook I / O w Pythonie , aby być użytecznym odniesienia, jak również.
import sys
for line in sys.stdin:
print(line)
Zauważ, że będzie to zawierać znak nowej linii na końcu. Aby usunąć nowy wiersz na końcu, użyj line.rstrip()
jak powiedział @brittohalloran.
\r\n
zakończeniami linii
Python ma również wbudowane funkcje input()
i raw_input()
. Zobacz dokumentację Pythona w części Funkcje wbudowane .
Na przykład,
name = raw_input("Enter your name: ") # Python 2.x
lub
name = input("Enter your name: ") # Python 3
Oto z Learning Python :
import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."
W systemie Unix możesz to przetestować, wykonując coś takiego:
% cat countlines.py | python countlines.py
Counted 3 lines.
W systemie Windows lub DOS:
C:\> type countlines.py | python countlines.py
Counted 3 lines.
print(sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, 1 << 15), '')))
. patrzwc-l.py
cat
tutaj jest zbędne. Prawidłowe wywołanie dla systemów uniksowych to python countlines.py < countlines.py
.
readlines()
. Obiekty plików mają być iterowane bez zmaterializowania wszystkich danych w pamięci.
Jak czytasz ze standardowego wejścia w Pythonie?
Próbuję wykonać niektóre wyzwania związane z golfem, ale wszystkie wymagają wkładu ze standardowego wejścia. Jak mogę to uzyskać w Pythonie?
Możesz użyć:
sys.stdin
- Obiekt podobny do pliku - wywołanie sys.stdin.read()
do odczytu wszystkiego.input(prompt)
- przekazać opcjonalny monit o wyjście, odczytuje ze standardowego wejścia do pierwszej nowej linii, którą usuwa. Musiałbyś to robić wielokrotnie, aby uzyskać więcej linii, na końcu wejścia podnosi EOFError. (Prawdopodobnie nie jest świetny do gry w golfa.) W Pythonie 2 tak jest rawinput(prompt)
.open(0).read()
- W Pythonie 3 wbudowana funkcja open
akceptuje deskryptory plików (liczby całkowite reprezentujące zasoby IO systemu operacyjnego), a 0 to deskryptor plikustdin
. Zwraca obiekt podobny do pliku sys.stdin
- prawdopodobnie najlepszy wybór do gry w golfa. W Pythonie 2 jest to io.open
.open('/dev/stdin').read()
- podobny do open(0)
, działa na Python 2 i 3, ale nie na Windows (lub nawet Cygwin).fileinput.input()
- zwraca iterator po liniach we wszystkich plikach wymienionych w sys.argv[1:]
lub stdin, jeśli nie podano. Użyj jak ''.join(fileinput.input())
.Oba sys
i fileinput
oczywiście muszą zostać zaimportowane.
sys.stdin
przykłady kompatybilne z Python 2 i 3, Windows, UnixTrzeba tylko read
od sys.stdin
, na przykład, jeśli dane rur do stdin:
$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo
Widzimy, że sys.stdin
jest w domyślnym trybie tekstowym:
>>> import sys
>>> sys.stdin
<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
Powiedzmy, że masz plik, inputs.txt
możemy go zaakceptować i zapisać ponownie:
python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
Oto kompletne, łatwe do odtworzenia demo, wykorzystujące dwie metody, wbudowaną funkcję input
(użycie raw_input
w Pythonie 2) i sys.stdin
. Dane są niezmodyfikowane, więc przetwarzanie nie jest wykonywane.
Na początek stwórzmy plik dla danych wejściowych:
$ python -c "print('foo\nbar\nbaz')" > inputs.txt
Korzystając z kodu, który już widzieliśmy, możemy sprawdzić, czy utworzyliśmy plik:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Oto pomoc sys.stdin.read
z 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
w Pythonie 2)Wbudowana funkcja input
odczytuje ze standardowego wejścia do nowej linii, która jest usuwana (uzupełniająca print
, która domyślnie dodaje nową linię). Dzieje się tak, dopóki nie otrzyma EOF (End Of File), w którym to momencie podnosi się EOFError
.
Oto, w jaki sposób możesz używać input
w Pythonie 3 (lub raw_input
w Pythonie 2) do czytania ze stdin - dlatego tworzymy moduł Pythona, który nazywamy stdindemo.py:
$ python -c "print('try:\n while True:\n print(input())\nexcept EOFError:\n pass')" > stdindemo.py
Wydrukujmy go ponownie, aby upewnić się, że jest zgodny z naszymi oczekiwaniami:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py
try:
while True:
print(input())
except EOFError:
pass
Znów input
czyta aż do nowej linii i zasadniczo usuwa ją z linii. print
dodaje nową linię. Tak więc, gdy obaj modyfikują dane wejściowe, ich modyfikacje są anulowane. (Więc są one wzajemnie uzupełnieniem).
A kiedy input
dostaje znak końca pliku, podnosi EOFError, który ignorujemy, a następnie wychodzimy z programu.
A w systemie Linux / Unix możemy przesyłać z cat:
$ cat inputs.txt | python -m stdindemo
foo
bar
baz
Lub możemy po prostu przekierować plik ze standardowego wejścia:
$ python -m stdindemo < inputs.txt
foo
bar
baz
Możemy również wykonać moduł jako skrypt:
$ python stdindemo.py < inputs.txt
foo
bar
baz
Oto pomoc dotycząca wbudowanego input
Pythona 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
Tutaj tworzymy skrypt demo przy użyciu sys.stdin
. Skutecznym sposobem na iterację obiektu podobnego do pliku jest użycie obiektu podobnego do pliku jako iteratora. Uzupełniającą metodą zapisu na standardowe wyjście z tego wejścia jest po prostu użycie sys.stdout.write
:
$ python -c "print('import sys\nfor line in sys.stdin:\n sys.stdout.write(line)')" > stdindemo2.py
Wydrukuj go ponownie, aby upewnić się, że wygląda poprawnie:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py
import sys
for line in sys.stdin:
sys.stdout.write(line)
I przekierowanie danych wejściowych do pliku:
$ python -m stdindemo2 < inputs.txt
foo
bar
baz
Grał w golfa w polecenie:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Ponieważ deskryptory plików dla stdin
i stdout
są odpowiednio 0 i 1, możemy również przekazać je do open
Pythona 3 (nie 2, i zauważ, że nadal potrzebujemy „w” do zapisu na standardowe wyjście).
Jeśli to zadziała w twoim systemie, zgoli więcej postaci.
$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo
Python 2 również to io.open
robi, ale import zajmuje dużo więcej miejsca:
$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt
foo
bar
baz
Jeden komentarz sugeruje ''.join(sys.stdin)
grę w golfa, ale w rzeczywistości jest on dłuższy niż sys.stdin.read () - a ponadto Python musi utworzyć dodatkową listę w pamięci (tak str.join
działa, gdy nie jest podana lista) - dla kontrastu:
''.join(sys.stdin)
sys.stdin.read()
Najlepsza odpowiedź sugeruje:
import fileinput
for line in fileinput.input():
pass
Ponieważ jednak sys.stdin
implementuje interfejs API pliku, w tym protokół iteratora, jest to dokładnie to samo:
import sys
for line in sys.stdin:
pass
Inna odpowiedź to sugeruje. Pamiętaj tylko, że jeśli zrobisz to w tłumaczu, musisz to zrobić Ctrl- djeśli korzystasz z systemu Linux lub Mac, lub Ctrl- zw systemie Windows (po Enter), aby wysłać znak końca pliku do procesu. Również ta odpowiedź sugeruje print(line)
- co dodaje '\n'
do końca - użycie print(line, end='')
zamiast tego (jeśli w Pythonie 2 będziesz potrzebować from __future__ import print_function
).
Prawdziwym przypadkiem użycia fileinput
jest odczytywanie w szeregu plików.
Odpowiedź zaproponowana przez innych:
for line in sys.stdin:
print line
jest bardzo prosty i pytoniczny, ale należy zauważyć, że skrypt zaczeka na EOF, zanim zacznie iterować na liniach wejściowych.
Oznacza to, że tail -f error_log | myscript.py
linie nie będą przetwarzane zgodnie z oczekiwaniami.
Prawidłowy skrypt dla takiego przypadku użycia to:
while 1:
try:
line = sys.stdin.readline()
except KeyboardInterrupt:
break
if not line:
break
print line
AKTUALIZACJA
Z komentarzy zostało wyjaśnione, że tylko w Pythonie może występować buforowanie, tak że w końcu czekasz na wypełnienie bufora lub EOF przed wydaniem wywołania drukowania.
for line in sys.stdin:
Wzór nie czekać na EOF. Ale jeśli testujesz na bardzo małych plikach, odpowiedzi mogą zostać buforowane. Przetestuj z większą ilością danych, aby zobaczyć, że odczytuje wyniki pośrednie.
print line
nie budzi się w 3.1.3, ale print(line)
tak.
for line in sys.stdin:
nie „blokuje do EOF”. W Pythonie 2 występuje błąd odczytu z wyprzedzeniem, który opóźnia linie do momentu zapełnienia odpowiedniego bufora. Jest to problem buforowania niezwiązany z EOF. Aby obejść ten problem, użyj for line in iter(sys.stdin.readline, ''):
(użyj io.open()
do zwykłych plików). Nie potrzebujesz go w Pythonie 3.
Opierając się na wszystkich anwersach sys.stdin
, możesz również zrobić coś takiego jak poniżej, aby odczytać z pliku argumentu, jeśli istnieje co najmniej jeden argument, i w przeciwnym razie powróć do standardowego wejścia:
import sys
f = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
for line in f:
# Do your stuff
i użyj go jako jednego z nich
$ python do-my-stuff.py infile.txt
lub
$ cat infile.txt | python do-my-stuff.py
lub nawet
$ python do-my-stuff.py < infile.txt
To sprawi, że Twój skrypt Pythona zachowuje się podobnie jak wiele programów GNU / Unix, takich jak cat
, grep
i sed
.
argparse
jest łatwym rozwiązaniemPrzykład zgodny z wersją 2 i 3 Pythona:
#!/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()
Możesz uruchomić ten skrypt na wiele sposobów:
1. Korzystanie stdin
echo 'foo bar' | ./above-script.py
lub krócej, zastępując echo
przez tutaj ciąg :
./above-script.py <<< 'foo bar'
2. Za pomocą argumentu nazwy pliku
echo 'foo bar' > my-file.data
./above-script.py my-file.data
3. Używanie stdin
specjalnej nazwy pliku-
echo 'foo bar' | ./above-script.py -
add_argument('--in'
a następnie potokować do skryptu i dodać --in -
do wiersza polecenia. PS in
nie jest bardzo dobrą nazwą dla zmiennej / atrybutu.
in
nie jest tylko złą nazwą zmiennej, jest nielegalna. args.in.read()
podniesie błąd InvalidSyntax z powodu in
zarezerwowanego słowa kluczowego. Można po prostu zmienić nazwę, aby infile
polubić python argparse docs: docs.python.org/3/library/…
Poniższy układ kodu pomoże ci (odczyta wszystkie stdin blokujące do EOF
, w jednym ciągu):
import sys
input_str = sys.stdin.read()
print input_str.split()
Jestem zdumiony, że nikt dotąd nie wspomniał o tym hacku:
python -c "import sys; set(map(sys.stdout.write,sys.stdin))"
w python2 możesz porzucić set()
połączenie, ale wyraziłoby to w obu kierunkach
readlines
tego podziału na linie, a potem join
znowu? Możesz po prostu napisaćprint(sys.stdin.read())
write
zwraca None
, a ustawiony rozmiar nigdy nie byłby większy niż 1 ( =len(set([None]))
)
Możesz czytać ze standardowego wejścia, a następnie przechowywać dane wejściowe w „danych” w następujący sposób:
data = ""
for line in sys.stdin:
data += line
data = sys.stdin.read()
bez problemu z powtarzającymi się łączeniami łańcuchów.
Czytaj z sys.stdin
, ale aby odczytać dane binarne w systemie Windows , musisz zachować szczególną ostrożność, ponieważ sys.stdin
jest on otwarty w trybie tekstowym i spowoduje uszkodzenie jego \r\n
zastąpienia \n
.
Rozwiązaniem jest ustawienie trybu na binarny, jeśli wykryty zostanie system Windows + Python 2, a także w przypadku języka 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()
Korzystam z następującej metody, zwraca ciąg ze stdin (używam go do parsowania json). Działa z potokiem i monitami w systemie Windows (jeszcze nie testowany w systemie Linux). Po wyświetleniu monitu dwa podziały linii wskazują koniec wprowadzania.
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
Problem z rozwiązaniem
import sys
for line in sys.stdin:
print(line)
polega na tym, że jeśli nie przekażesz żadnych danych do standardowego wejścia, zostanie ono zablokowane na zawsze. Dlatego uwielbiam tę odpowiedź : najpierw sprawdź, czy są jakieś dane dotyczące standardowego wejścia, a następnie je przeczytaj. Tak właśnie skończyłem:
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)
select
zostanie wywołane; lub możesz napotkać problemy, jeśli stdin jest podłączony do pliku na wolnym nośniku (sieć, płyta CD, taśma itp.). Powiedziałeś, że „jeśli nie przekażesz żadnych danych do standardowego wejścia, zablokuje ono na zawsze”. jest problemem , ale powiedziałbym, że to funkcja . Większość programów CLI (np. cat
) Działa w ten sposób i oczekuje się tego. EOF jest jedyną rzeczą, na której powinieneś polegać, aby wykryć koniec danych wejściowych.
Miałem pewne problemy z uruchomieniem tego do odczytu przez podłączone do niego gniazda. Kiedy gniazdo zostało zamknięte, zaczęło zwracać pusty ciąg w aktywnej pętli. To jest moje rozwiązanie (które testowałem tylko w systemie Linux, ale mam nadzieję, że zadziała we wszystkich innych systemach)
import sys, os
sep=os.linesep
while sep == os.linesep:
data = sys.stdin.readline()
sep = data[-len(os.linesep):]
print '> "%s"' % data.strip()
Więc jeśli zaczniesz nasłuchiwać na gnieździe, będzie działało poprawnie (np. W bash):
while :; do nc -l 12345 | python test.py ; done
Możesz to nazwać telnetem lub po prostu skierować przeglądarkę na localhost: 12345
Odnośnie tego:
for line in sys.stdin:
Właśnie wypróbowałem go w Pythonie 2.7 (zgodnie z sugestią kogoś innego) dla bardzo dużego pliku i nie polecam go, właśnie z wyżej wymienionych powodów (nic się nie dzieje przez długi czas).
Skończyło się na nieco bardziej pythonowym rozwiązaniu (i działa na większych plikach):
with open(sys.argv[1], 'r') as f:
for line in f:
Następnie mogę uruchomić skrypt lokalnie jako:
python myscript.py "0 1 2 3 4..." # can be a multi-line string or filename - any std.in input will work
sys.stdin
do skryptu argument wiersza polecenia.
sys.stdin
skrypt jako argument wiersza poleceń? Argumenty są łańcuchami, a strumienie są obiektami podobnymi do plików, nie są takie same.
sys.stdin
to plikopodobnym obiektu
Dla Pythona 3 byłoby to:
# Filename e.g. cat.py
import sys
for line in sys.stdin:
print(line, end="")
Jest to w zasadzie prosta forma cat (1), ponieważ nie dodaje nowej linii po każdej linii. Możesz użyć tego (po oznaczeniu pliku wykonywalnego za pomocą chmod +x cat.py
:
echo Hello | ./cat.py
Podczas korzystania z -c
polecenia, jako trudnego sposobu, zamiast czytać stdin
(a w niektórych przypadkach bardziej elastyczny) można przekazać polecenie skryptu powłoki również do polecenia python, umieszczając polecenie sprzedaży w cudzysłowie w nawiasach rozpoczynanych $
znakiem.
na przykład
python3 -c "import sys; print(len(sys.argv[1].split('\n')))" "$(cat ~/.goldendict/history)"
Policzy to liczbę linii z pliku historii goldendict.