Risposte:
È possibile utilizzare il fileinput
modulo:
import fileinput
for line in fileinput.input():
pass
fileinput
scorrerà in sequenza tutte le righe dell'input specificato come nome file indicato negli argomenti della riga di comando o l'input standard se non viene fornito alcun argomento.
Nota: line
conterrà una nuova riga finale; per rimuoverlo utilizzareline.rstrip()
Ci sono alcuni modi per farlo.
sys.stdin
è un oggetto simile a un file su cui è possibile chiamare funzioni read
o readlines
se si desidera leggere tutto o si desidera leggere tutto e dividerlo automaticamente per newline. (È necessario import sys
per farlo funzionare.)
Se si desidera richiedere all'utente l'input, è possibile utilizzare raw_input
in Python 2.X e solo input
in Python 3.
Se in realtà vuoi solo leggere le opzioni della riga di comando, puoi accedervi tramite l' elenco sys.argv .
Probabilmente troverai questo articolo di Wikibook su I / O in Python come utile riferimento.
import sys
for line in sys.stdin:
print(line)
Si noti che questo includerà un carattere di nuova riga alla fine. Per rimuovere la nuova riga alla fine, utilizzare line.rstrip()
come ha detto @brittohalloran.
\r\n
terminazioni di riga
Python ha anche funzioni integrate input()
e raw_input()
. Consulta la documentazione di Python in Funzioni integrate .
Per esempio,
name = raw_input("Enter your name: ") # Python 2.x
o
name = input("Enter your name: ") # Python 3
Ecco da Learning Python :
import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."
Su Unix, potresti provarlo facendo qualcosa del tipo:
% cat countlines.py | python countlines.py
Counted 3 lines.
Su Windows o DOS, dovresti:
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), '')))
. vediwc-l.py
cat
qui è ridondante. L'invocazione corretta per i sistemi Unix è python countlines.py < countlines.py
.
readlines()
. Gli oggetti file devono essere ripetuti senza materializzare tutti i dati in memoria.
Come leggi dallo stdin in Python?
Sto provando a fare alcune delle sfide del golf del codice, ma tutte richiedono che l'input sia preso dallo stdin. Come posso ottenerlo in Python?
Puoi usare:
sys.stdin
- Un oggetto simile a un file: chiama sys.stdin.read()
per leggere tutto.input(prompt)
- passare un prompt opzionale per l'output, legge da stdin fino alla prima nuova riga, che si spoglia. Dovresti farlo ripetutamente per ottenere più righe, alla fine dell'input genera EOFError. (Probabilmente non eccezionale per il golf.) In Python 2, questo è rawinput(prompt)
.open(0).read()
- In Python 3, la funzione integrata open
accetta i descrittori di file (numeri interi che rappresentano risorse IO del sistema operativo) e 0 è il descrittore di stdin
. Restituisce un oggetto simile a un file, sys.stdin
probabilmente la soluzione migliore per giocare a golf. In Python 2, questo è io.open
.open('/dev/stdin').read()
- simile a open(0)
, funziona su Python 2 e 3, ma non su Windows (o persino Cygwin).fileinput.input()
- restituisce un iteratore su righe in tutti i file elencati in sys.argv[1:]
, oppure stdin se non specificato. Usa come ''.join(fileinput.input())
.Entrambi sys
e fileinput
devono essere importati, ovviamente, ovviamente.
sys.stdin
Esempi rapidi compatibili con Python 2 e 3, Windows, UnixHai solo bisogno di read
da sys.stdin
, per esempio, se si i dati di tubo a STDIN:
$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo
Possiamo vedere che sys.stdin
è in modalità testo predefinita:
>>> import sys
>>> sys.stdin
<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
Supponiamo che tu abbia un file, inputs.txt
possiamo accettarlo e riscriverlo:
python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
Ecco una demo completa, facilmente replicabile, usando due metodi, la funzione integrata, input
(usare raw_input
in Python 2) e sys.stdin
. I dati non sono modificati, pertanto l'elaborazione non è operativa.
Per cominciare, creiamo un file per gli input:
$ python -c "print('foo\nbar\nbaz')" > inputs.txt
E usando il codice che abbiamo già visto, possiamo verificare che abbiamo creato il file:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Ecco l'aiuto sys.stdin.read
di 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
in Python 2)La funzione incorporata input
legge dallo standard input fino a una nuova riga, che viene rimossa (complementare print
, che aggiunge una nuova riga per impostazione predefinita). Ciò si verifica fino a quando non ottiene EOF (End Of File), a quel punto si alza EOFError
.
Quindi, ecco come puoi usare input
in Python 3 (o raw_input
in Python 2) per leggere da stdin - quindi creiamo un modulo Python che chiamiamo stdindemo.py:
$ python -c "print('try:\n while True:\n print(input())\nexcept EOFError:\n pass')" > stdindemo.py
E stampiamolo indietro per assicurarci che sia come ci aspettiamo:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py
try:
while True:
print(input())
except EOFError:
pass
Ancora una volta, input
legge fino alla nuova riga e sostanzialmente lo toglie dalla riga. print
aggiunge una nuova riga. Quindi, mentre entrambi modificano l'input, le loro modifiche si annullano. (Quindi sono essenzialmente il complemento reciproco.)
E quando input
ottiene il carattere di fine file, genera EOFError, che ignoriamo e quindi usciamo dal programma.
E su Linux / Unix, possiamo pipe da cat:
$ cat inputs.txt | python -m stdindemo
foo
bar
baz
Oppure possiamo semplicemente reindirizzare il file da stdin:
$ python -m stdindemo < inputs.txt
foo
bar
baz
Possiamo anche eseguire il modulo come script:
$ python stdindemo.py < inputs.txt
foo
bar
baz
Ecco l'aiuto sull'integrato input
da 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
Qui facciamo uno script demo usando sys.stdin
. Il modo più efficiente per scorrere su un oggetto simile a un file è utilizzare l'oggetto simile a un file come iteratore. Il metodo complementare per scrivere su stdout da questo input è semplicemente usare sys.stdout.write
:
$ python -c "print('import sys\nfor line in sys.stdin:\n sys.stdout.write(line)')" > stdindemo2.py
Stampalo di nuovo per assicurarti che appaia bene:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py
import sys
for line in sys.stdin:
sys.stdout.write(line)
E reindirizzando gli input nel file:
$ python -m stdindemo2 < inputs.txt
foo
bar
baz
Lanciato in un comando:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Poiché i descrittori di file per stdin
e stdout
sono rispettivamente 0 e 1, possiamo anche passarli a open
in Python 3 (non 2, e notiamo che abbiamo ancora bisogno della 'w' per scrivere su stdout).
Se funziona sul tuo sistema, eliminerà più caratteri.
$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo
Anche Python 2 io.open
fa questo, ma l'importazione occupa molto più spazio:
$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt
foo
bar
baz
Un commento suggerisce ''.join(sys.stdin)
per il golf, ma in realtà è più lungo di sys.stdin.read () - inoltre Python deve creare un elenco aggiuntivo in memoria (è così che str.join
funziona quando non viene fornito un elenco) - per contrasto:
''.join(sys.stdin)
sys.stdin.read()
La risposta migliore suggerisce:
import fileinput
for line in fileinput.input():
pass
Ma, poiché sys.stdin
implementa l'API di file, incluso il protocollo iteratore, è esattamente lo stesso di questo:
import sys
for line in sys.stdin:
pass
Un'altra risposta non suggerire questo. Ricorda solo che se lo fai in un interprete, dovrai farlo Ctrl- dse sei su Linux o Mac, o Ctrl- zsu Windows (dopo Enter) per inviare il carattere di fine file al processo. Inoltre, quella risposta suggerisce print(line)
- che aggiunge un '\n'
alla fine - usa print(line, end='')
invece (se in Python 2, avrai bisogno from __future__ import print_function
).
Il vero caso d'uso fileinput
è per la lettura in una serie di file.
La risposta proposta da altri:
for line in sys.stdin:
print line
è molto semplice e pitonico, ma va notato che lo script attenderà EOF prima di iniziare a iterare sulle righe di input.
Ciò significa che tail -f error_log | myscript.py
non elaborerà le linee come previsto.
Lo script corretto per tale caso d'uso sarebbe:
while 1:
try:
line = sys.stdin.readline()
except KeyboardInterrupt:
break
if not line:
break
print line
AGGIORNAMENTO
Dai commenti è stato chiarito che su Python 2 potrebbe essere coinvolto solo il buffering, quindi si finisce per attendere che il buffer si riempia o EOF prima che venga emessa la chiamata di stampa.
for line in sys.stdin:
schema no attende EOF. Ma se esegui test su file di dimensioni molto ridotte, le risposte potrebbero essere memorizzate nel buffer. Prova con più dati per vedere che legge risultati intermedi.
print line
non si sveglia in 3.1.3, ma lo print(line)
fa.
for line in sys.stdin:
non "blocca fino a EOF". Esiste un bug read-ahead in Python 2 che ritarda le righe fino a quando il buffer corrispondente è pieno. Si tratta di un problema di buffering non correlato a EOF. Per risolvere il problema, utilizzare for line in iter(sys.stdin.readline, ''):
(utilizzare io.open()
per file ordinari). Non ne hai bisogno in Python 3.
Sulla base di tutte le risposte che usano sys.stdin
, puoi anche fare qualcosa di simile al seguente per leggere da un file di argomenti se esiste almeno un argomento, e ricorrere allo stdin altrimenti:
import sys
f = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
for line in f:
# Do your stuff
e usalo come uno dei due
$ python do-my-stuff.py infile.txt
o
$ cat infile.txt | python do-my-stuff.py
o anche
$ python do-my-stuff.py < infile.txt
Ciò renderebbe il tuo script Python comportarsi come molti programmi GNU / Unix come cat
, grep
e sed
.
argparse
è una soluzione facileEsempio compatibile con entrambe le versioni Python 2 e 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()
Puoi eseguire questo script in molti modi:
1. Utilizzo stdin
echo 'foo bar' | ./above-script.py
o più breve sostituendo echo
con qui stringa :
./above-script.py <<< 'foo bar'
2. Utilizzo di un argomento per il nome file
echo 'foo bar' > my-file.data
./above-script.py my-file.data
3. Utilizzo stdin
tramite il nome file speciale-
echo 'foo bar' | ./above-script.py -
add_argument('--in'
e poi reindirizzare allo script e aggiungere --in -
alla riga di comando. PS in
non è un nome molto valido per una variabile / attributo.
in
non è solo un brutto nome per una variabile, è illegale. args.in.read()
genererà l'errore InvalidSyntax a causa della in
parola chiave riservata. Può semplicemente rinominare infile
come fanno i documenti di Python Argparse: docs.python.org/3/library/…
Il seguente chip di codice ti aiuterà (leggerà tutto il blocco stdin EOF
in, in una stringa):
import sys
input_str = sys.stdin.read()
print input_str.split()
Sono piuttosto sorpreso che nessuno abbia menzionato questo hack finora:
python -c "import sys; set(map(sys.stdout.write,sys.stdin))"
in python2 puoi abbandonare la set()
chiamata, ma sarebbe una parola in entrambi i modi
readlines
quella divisione in linee e poi di join
nuovo? Puoi semplicemente scrivereprint(sys.stdin.read())
write
ritorna None
e la dimensione impostata non sarebbe mai maggiore di 1 ( =len(set([None]))
)
È possibile leggere da stdin e quindi memorizzare gli input in "dati" come segue:
data = ""
for line in sys.stdin:
data += line
data = sys.stdin.read()
, senza il problema di ripetute concatenazioni di stringhe.
Leggi da sys.stdin
, ma per leggere i dati binari su Windows , devi essere molto attento, perché sys.stdin
è aperto in modalità testo e corromperà \r\n
sostituendoli con \n
.
La soluzione è impostare la modalità su binario se viene rilevato Windows + Python 2 e su Python 3 utilizzare 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()
Uso il seguente metodo, restituisce una stringa da stdin (la uso per l'analisi json). Funziona con pipe e prompt su Windows (non ancora testato su Linux). Quando richiesto, due interruzioni di riga indicano la fine dell'input.
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
Il problema che ho con la soluzione
import sys
for line in sys.stdin:
print(line)
è che se non passi alcun dato a stdin, si bloccherà per sempre. Ecco perché adoro questa risposta : controlla prima che ci siano alcuni dati su stdin e poi leggili. Questo è quello che ho finito per fare:
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
viene chiamato; oppure potresti anche riscontrare problemi se stdin è collegato a un file su un supporto lento (rete, CD, nastro, ecc.). Hai detto che "se non passi alcun dato a stdin, si bloccherà per sempre". è un problema , ma direi che è una caratteristica . La maggior parte dei programmi CLI (ad es. cat
) Funzionano in questo modo e sono previsti. EOF è l'unica cosa da cui dovresti dipendere per rilevare la fine dell'input.
Ho avuto dei problemi quando riuscivo a farlo funzionare per leggere su socket collegati ad esso. Quando il socket è stato chiuso, ha iniziato a restituire una stringa vuota in un loop attivo. Quindi questa è la mia soluzione (che ho testato solo su Linux, ma spero che funzioni in tutti gli altri sistemi)
import sys, os
sep=os.linesep
while sep == os.linesep:
data = sys.stdin.readline()
sep = data[-len(os.linesep):]
print '> "%s"' % data.strip()
Quindi se inizi ad ascoltare su un socket funzionerà correttamente (es. In bash):
while :; do nc -l 12345 | python test.py ; done
E puoi chiamarlo con telnet o semplicemente puntare un browser a localhost: 12345
A riguardo:
for line in sys.stdin:
L'ho appena provato su Python 2.7 (seguendo il suggerimento di qualcun altro) per un file molto grande, e non lo consiglio, proprio per i motivi sopra menzionati (non succede nulla per molto tempo).
Ho finito con una soluzione leggermente più pitonica (e funziona su file più grandi):
with open(sys.argv[1], 'r') as f:
for line in f:
Quindi posso eseguire lo script localmente come:
python myscript.py "0 1 2 3 4..." # can be a multi-line string or filename - any std.in input will work
sys.stdin
come argomento da riga di comando allo script.
sys.stdin
come argomento della riga di comando allo script? Gli argomenti sono stringhe e gli stream sono oggetti simili a file, non sono gli stessi.
sys.stdin
è un oggetto simile a un file
Per Python 3 sarebbe:
# Filename e.g. cat.py
import sys
for line in sys.stdin:
print(line, end="")
Questa è fondamentalmente una semplice forma di gatto (1), poiché non aggiunge una nuova riga dopo ogni riga. È possibile utilizzare questo (dopo aver contrassegnato il file eseguibile utilizzando chmod +x cat.py
come:
echo Hello | ./cat.py
Quando si utilizza il -c
comando, come un modo complicato, invece di leggere il stdin
(e più flessibile in alcuni casi) è possibile passare un comando di script shell anche al comando python inserendo il comando sell tra virgolette all'interno di una parentesi iniziata da $
segno.
per esempio
python3 -c "import sys; print(len(sys.argv[1].split('\n')))" "$(cat ~/.goldendict/history)"
Questo conterà il numero di righe dal file cronologico di goldendict.