web-dev-qa-db-fra.com

Comment lisez-vous de stdin?

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?

1264
tehryan

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()

854
u0b34a0f6ae

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.

636
Mark Rushakoff
import sys

for line in sys.stdin:
    print line
364
user303110

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
200
Pat Notz

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.
173
Eugene Yokota

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.

91

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, openaccepte descripteurs de fichier (entiers représentant le système d'exploitation IO ressources), et 0 est le descripteur de stdinname__. 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()).

syset fileinputdoivent être importés, respectivement, bien sûr.

Exemples rapides sys.stdin compatibles avec Python 2 et 3, Windows, Unix

Il 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

exemple de fichier

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

Réponse plus longue

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.

Fonction intégrée, input(raw_input in Python 2)

La fonction intégrée inputlit depuis l'entrée standard jusqu'à une nouvelle ligne, qui est supprimée (complétant printname__, qui ajoute une nouvelle ligne par défaut.) Cela se produit jusqu'à l'obtention de EOF (End Of File), auquel point soulève EOFErrorname__.

Voici donc comment utiliser inputen 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, inputse lit jusqu'à la nouvelle ligne et la supprime essentiellement de la ligne. printajoute 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 inputobtient 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é inputde 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

Descripteurs de fichiers pour le golf

Étant donné que les descripteurs de fichier pour stdinet stdoutsont respectivement 0 et 1, nous pouvons également les transmettre à opendans 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

Répondre à d'autres commentaires et réponses

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 fileinputest destiné à la lecture d'une série de fichiers.

76
Aaron Hall

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()
35
rlib

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.

30
Emil Lundberg

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()
14
Chandan Kumar

argparse est une solution simple

Exemple 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 -
8
olibre

Vous pouvez lire depuis stdin puis stocker les entrées dans "data" comme suit:

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

Essaye ça:

import sys

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

et le vérifier avec:

$ echo "Hello World" | python myFile.py
7
Boubakr

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

6
Uri Goren

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()
5
anatoly techtonik

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)
3
SummerBreeze

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

2
estani

À 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
1
szeitlin

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 ()

0
Jay

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.

0
Kasrâmvd

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
0
AdamKalisz
n = int(raw_input())
for i in xrange(n):
    name, number = raw_input().split()
0
issam