J'essaie de relever quelques-uns des défis code golf , mais ils nécessitent tous que les données soient extraites de stdin
. Comment puis-je obtenir cela en Python?
Vous pouvez utiliser le module fileinput
:
import fileinput
for line in fileinput.input():
pass
fileinput
parcourra toutes les lignes de l'entrée spécifiée sous la forme de noms de fichiers donnés dans les arguments de ligne de commande ou l'entrée standard si aucun argument n'est fourni.
Remarque: line
contiendra un retour à la ligne; pour l'enlever, utilisez line.rstrip()
Il y a plusieurs façons de le faire.
sys.stdin
est un objet de type fichier sur lequel vous pouvez appeler des fonctions read
ou readlines
si vous voulez tout lire ou si vous voulez tout lire et le scinder automatiquement par une nouvelle ligne. (Vous devez import sys
pour que cela fonctionne.)
Si vous voulez Inviter l'utilisateur à entrer, vous pouvez utiliser raw_input
en Python 2.X et juste input
en Python 3.
Si vous voulez simplement lire les options de ligne de commande, vous pouvez y accéder via la liste sys.argv .
Vous trouverez probablement cet article de Wikibook sur les E/S en Python également une référence utile.
import sys
for line in sys.stdin:
print line
Python possède également les fonctions intégrées input()
et raw_input()
. Voir la documentation Python sous Fonctions intégrées .
Par exemple,
name = raw_input("Enter your name: ") # Python 2.x
ou
name = input("Enter your name: ") # Python 3
Voici de Learning Python :
import sys
data = sys.stdin.readlines()
print "Counted", len(data), "lines."
Sous Unix, vous pouvez le tester en faisant quelque chose comme:
% cat countlines.py | python countlines.py
Counted 3 lines.
Sous Windows ou DOS, vous feriez:
C:\> type countlines.py | python countlines.py
Counted 3 lines.
La réponse proposée par d'autres:
for line in sys.stdin:
print line
est très simple et Pythonic, mais il faut noter que le script attendra jusqu'à EOF avant de commencer à itérer sur les lignes d'entrée.
Cela signifie que tail -f error_log | myscript.py
ne traitera pas les lignes comme prévu.
Le script correct pour un tel cas d'utilisation serait:
while 1:
try:
line = sys.stdin.readline()
except KeyboardInterrupt:
break
if not line:
break
print line
METTRE À JOUR
D'après les commentaires, il a été précisé que sur Python 2 uniquement, la mise en mémoire tampon pouvait être impliquée, de sorte que vous attendiez que le tampon se remplisse ou EOF avant que l'appel à l'impression soit émis.
Comment lisez-vous de stdin en Python?
J'essaie de relever certains des défis du code de golf, mais ils nécessitent tous que l'entrée soit prise de stdin. Comment puis-je obtenir cela en Python?
Vous pouvez utiliser:
sys.stdin
- Objet de type fichier - appelez sys.stdin.read()
pour tout lire.input(Prompt)
- transmettez-lui une invite facultative à la sortie, elle lit de stdin jusqu'à la première nouvelle ligne, qu'elle dépouille. Vous devrez faire cela à plusieurs reprises pour obtenir plus de lignes. À la fin de l'entrée, cela soulève EOFError. (Probablement pas idéal pour jouer au golf.) En Python 2, c'est rawinput(Prompt)
.open(0).read()
- En Python 3, open
accepte descripteurs de fichier (entiers représentant le système d'exploitation IO ressources), et 0 est le descripteur de stdin
name__. Il retourne un objet de type fichier tel que sys.stdin
- probablement votre meilleur choix pour le golf.open('/dev/stdin').read()
- similaire à open(0)
, fonctionne sur Python 2 et 3, mais pas sur Windows (ni même Cygwin).fileinput.input()
- renvoie un itérateur sur les lignes de tous les fichiers énumérés dans sys.argv[1:]
, ou stdin s'il n'est pas indiqué. Utilisez comme ''.join(fileinput.input())
.sys
et fileinput
doivent être importés, respectivement, bien sûr.
sys.stdin
compatibles avec Python 2 et 3, Windows, UnixIl vous suffit de read
à partir de sys.stdin
, par exemple, si vous dirigez les données vers stdin:
$ echo foo | python -c "import sys; print(sys.stdin.read())"
foo
Supposons que vous avez un fichier, inputs.txt
, nous pouvons accepter ce fichier et le réécrire:
python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
Voici une démo complète, facilement reproductible, utilisant deux méthodes, la fonction intégrée, input
(utilisez raw_input
en Python 2), et sys.stdin
. Les données ne sont pas modifiées, le traitement est donc une non-opération.
Pour commencer, créons un fichier pour les entrées:
$ python -c "print('foo\nbar\nbaz')" > inputs.txt
Et en utilisant le code que nous avons déjà vu, nous pouvons vérifier que nous avons créé le fichier:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Voici l'aide sur sys.stdin.read
de 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 fonction intégrée input
lit depuis l'entrée standard jusqu'à une nouvelle ligne, qui est supprimée (complétant print
name__, qui ajoute une nouvelle ligne par défaut.) Cela se produit jusqu'à l'obtention de EOF (End Of File), auquel point soulève EOFError
name__.
Voici donc comment utiliser input
en Python 3 (ou raw_input
en Python 2) pour lire à partir de stdin - nous avons donc créé un module Python appelé stdindemo.py:
$ python -c "print('try:\n while True:\n print(input())\nexcept EOFError:\n pass')" > stdindemo.py
Et réimprimons-le pour nous assurer que tout se passe comme prévu:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo.py
try:
while True:
print(input())
except EOFError:
pass
De nouveau, input
se lit jusqu'à la nouvelle ligne et la supprime essentiellement de la ligne. print
ajoute une nouvelle ligne. Ainsi, pendant qu'ils modifient tous les deux l'entrée, leurs modifications s'annulent. (Ils sont donc essentiellement complémentaires les uns des autres.)
Et lorsque input
obtient le caractère de fin de fichier, il déclenche EOFError, que nous ignorons puis sortons du programme.
Et sur Linux/Unix, nous pouvons canaliser à partir de cat:
$ cat inputs.txt | python -m stdindemo
foo
bar
baz
Ou nous pouvons simplement rediriger le fichier depuis stdin:
$ python -m stdindemo < inputs.txt
foo
bar
baz
Nous pouvons également exécuter le module en tant que script:
$ python stdindemo.py < inputs.txt
foo
bar
baz
Voici l'aide sur le fichier intégré input
de 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
Ici, nous faisons un script de démonstration en utilisant sys.stdin
. La méthode efficace pour parcourir un objet de type fichier consiste à utiliser cet objet comme un itérateur. La méthode complémentaire pour écrire sur stdout à partir de cette entrée consiste simplement à utiliser sys.stdout.write
:
$ python -c "print('import sys\nfor line in sys.stdin:\n sys.stdout.write(line)')" > stdindemo2.py
Imprimez-le pour vous assurer qu'il a l'air correct:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < stdindemo2.py
import sys
for line in sys.stdin:
sys.stdout.write(line)
Et rediriger les entrées dans le fichier:
$ python -m stdindemo2 < inputs.txt
foo
bar
baz
Golfé dans une commande:
$ python -c "import sys; sys.stdout.write(sys.stdin.read())" < inputs.txt
foo
bar
baz
Étant donné que les descripteurs de fichier pour stdin
et stdout
sont respectivement 0 et 1, nous pouvons également les transmettre à open
dans Python 3 (pas 2, et notez que nous avons toujours besoin du 'w' pour écrire sur stdout).
Si cela fonctionne sur votre système, il supprimera plus de caractères.
$ python -c "open(1,'w').write(open(0).read())" < inputs.txt
baz
bar
foo
Le io.open
de Python 2 le fait aussi, mais l'importation prend beaucoup plus de place:
$ python -c "from io import open; open(1,'w').write(open(0).read())" < inputs.txt
foo
bar
baz
Un commentaire suggère ''.join(sys.stdin)
mais est en réalité plus long que sys.stdin.read () - plus Python doit créer une liste supplémentaire en mémoire (c'est comme ça que str.join
fonctionne sans liste) - pour le contraste:
''.join(sys.stdin)
sys.stdin.read()
La réponse supérieure suggère:
import fileinput
for line in fileinput.input():
pass
Mais, puisque sys.stdin
implémente l'API de fichier, y compris le protocole itérateur, c'est la même chose que ceci:
import sys
for line in sys.stdin:
pass
Une autre réponse suggère . Rappelez-vous simplement que si vous le faites dans un interprète, vous devrez faire Ctrl-d si vous êtes sur Linux ou Mac, ou Ctrl-z sous Windows (après Enter) pour envoyer le caractère de fin de fichier au processus. De plus, cette réponse suggère print(line)
- qui ajoute un '\n'
à l'utilisateur final print(line, end='')
(si vous utilisez Python 2, vous aurez besoin de from __future__ import print_function
).
Le cas d'utilisation réel de fileinput
est destiné à la lecture d'une série de fichiers.
Cela fera écho de l'entrée standard à la sortie standard:
import sys
line = sys.stdin.readline()
while line:
print line,
line = sys.stdin.readline()
En vous basant sur toutes les réponses utilisant sys.stdin
, vous pouvez également procéder de la manière suivante pour lire à partir d'un fichier d'arguments s'il existe au moins un argument et revenir à stdin sinon:
import sys
f = open(sys.argv[1]) if len(sys.argv) > 1 else sys.stdin
for line in f:
# Do your stuff
et l'utiliser comme
$ python do-my-stuff.py infile.txt
ou
$ cat infile.txt | python do-my-stuff.py
ou même
$ python do-my-stuff.py < infile.txt
Cela ferait que votre script Python se comporte comme bon nombre de programmes GNU/Unix tels que cat
, grep
et sed
.
La puce de code suivante vous aidera (elle lira l’ensemble du blocage stdin jusqu’à EOF
dans une chaîne):
import sys
input_str = sys.stdin.read()
print input_str.split()
argparse
est une solution simpleExemple compatible avec les versions 2 et 3 de Python:
#!/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()
Vous pouvez exécuter ce script de plusieurs manières:
1. Utilisation de stdin
echo 'foo bar' | ./above-script.py
ou plus court en remplaçant echo
par icichaîne :
./above-script.py <<< 'foo bar'
2. Utilisation d'un argument de nom de fichier
echo 'foo bar' > my-file.data
./above-script.py my-file.data
3. Utilisation de stdin
par le nom de fichier spécial -
echo 'foo bar' | ./above-script.py -
Vous pouvez lire depuis stdin puis stocker les entrées dans "data" comme suit:
data = ""
for line in sys.stdin:
data += line
Essaye ça:
import sys
print sys.stdin.read().upper()
et le vérifier avec:
$ echo "Hello World" | python myFile.py
Je suis assez étonné que personne ne l'ait mentionné jusqu'à présent:
python -c "import sys;print (''.join([l for l in sys.stdin.readlines()]))"
compatible avec python2 et python3
Lisez à partir de sys.stdin
, mais pour lire des données binaires sous Windows, vous devez faire très attention, car sys.stdin
est ouvert en mode texte et il va corrompre \r\n
en les remplaçant par \n
.
La solution consiste à définir le mode sur binaire si Windows + Python 2 est détecté et sur Python 3, utilisez 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()
Le problème que j'ai avec la solution
import sys
for line in sys.stdin:
print(line)
est-ce que si vous ne transmettez aucune donnée à stdin, cela bloquera pour toujours. C'est pourquoi j'aime cette réponse : vérifie s'il existe des données sur stdin en premier, puis lis-les. C'est ce que j'ai fini par faire:
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)
J'ai eu quelques problèmes pour que cela fonctionne pour pouvoir lire par des socles. Lorsque le socket a été fermé, il a commencé à retourner une chaîne vide dans une boucle active. Voici donc ma solution (que je n’ai testée que sous Linux, mais espérons que cela fonctionne dans tous les autres systèmes)
import sys, os
sep=os.linesep
while sep == os.linesep:
data = sys.stdin.readline()
sep = data[-len(os.linesep):]
print '> "%s"' % data.strip()
Donc, si vous commencez à écouter sur une socket, cela fonctionnera correctement (par exemple, en bash):
while :; do nc -l 12345 | python test.py ; done
Et vous pouvez l'appeler avec telnet ou simplement pointer un navigateur sur localhost: 12345
À ce sujet:
for line in sys.stdin:
Je viens de l'essayer sur python 2.7 (suivant la suggestion de quelqu'un d'autre) pour un très gros fichier, et je ne le recommande pas, précisément pour les raisons mentionnées ci-dessus (rien ne se passe depuis longtemps).
Je me suis retrouvé avec une solution légèrement plus pythonique (et cela fonctionne sur des fichiers plus volumineux):
with open(sys.argv[1], 'r') as f:
for line in f:
Ensuite, je peux exécuter le script localement en tant que:
python myscript.py "0 1 2 3 4..." # can be a multi-line string or filename - any std.in input will work
Il y a os.read(0, x)
qui lit les xbytes à partir de 0 qui représente stdin. C'est une lecture sans tampon, plus faible que sys.stdin.read ()
Lorsque vous utilisez la commande -c
, de manière délicate, au lieu de lire le stdin
(et plus souple dans certains cas), vous pouvez également transmettre une commande de script shell à votre commande python. en mettant la commande de vente entre guillemets dans une parenthèse commencée par le signe $
.
par exemple.
python3 -c "import sys; print(len(sys.argv[1].split('\n')))" "$(cat ~/.goldendict/history)"
Cela comptera le nombre de lignes du fichier d'historique de goldendict.
Pour Python 3 ce serait:
# Filename e.g. cat.py
import sys
for line in sys.stdin:
print(line, end="")
Il s’agit d’une forme simple de cat (1), car elle n’ajoute pas de nouvelle ligne après chaque ligne. Vous pouvez utiliser ceci (après avoir marqué le fichier exécutable en utilisant chmod +x cat.py
tel que:
echo Hello | ./cat.py
n = int(raw_input())
for i in xrange(n):
name, number = raw_input().split()