Pipes et invites dans les scripts Python CLI

Est-il possible de combiner des invites en entrée et des invites TTY dans les scripts Python CLI? Par exemple, en lançant ceci:

import sys piped_text = None if not sys.stdin.isatty(): piped_text = sys.stdin.read() user_in = raw_input('Enter something: ') if piped_text: sys.stdout.write(piped_text) sys.stdout.write(user_in + '\n') 

Produit la sortie suivante:

 ~: python mrprompt.py Enter something: something something ~: echo foo | python mrprompt.py Enter something: Traceback (most recent call last): File "mrprompt.py", line 9, in  user_in = raw_input('Enter something: ') EOFError: EOF when reading a line 

Voici le résultat de ma recherche:

 ~: python mrprompt.py Enter something: something something ~: echo foo | python mrprompt.py Enter something: something foo something 

Je suppose, libellé différemment, est-il possible pour un sous-shell de connaître le tty de son shell parent? Est-il possible, en Python, d’interagir avec le tty d’un shell parent? J’utilise bash dans GNU Screen (par conséquent, la lecture de la variable d’environnement ‘SSH_TTY’ n’est pas une option viable).

Cela fonctionne plus ou moins:

 #!/usr/bin/python import sys saved_stdin = sys.stdin sys.stdin = open('/dev/tty', 'r') result = raw_input('Enter something: ') sys.stdout.write('Got: ' + result + '\n') sys.stdin = saved_stdin result2 = sys.stdin.read() sys.stdout.write('Also got: ' + result2) 

Enregistrer sous foo.py et essayez echo goodbye | ./foo.py echo goodbye | ./foo.py

Bien sûr, /dev/tty n’existe que sous Unix. Et si vous l’exécutez dans un processus sans terminal de contrôle, open() échouera probablement …

Vous pouvez détecter si votre stdin provient d’un tube ou non, comme vous le faites avec sys.stdin.isatty . Vous obtenez l’ EOF parce que vous lisez toutes les entrées avec le stdin.read() , puis vous essayez d’en lire plus avec la commande raw_input() .

Ce que vous ne pouvez pas faire, c’est à la fois de canaliser les entrées et de faire des entrées interactives. Si vous entrez des entrées dans le raw_input , il n’y a pas d’autre stdin contre raw_input travailler avec raw_input . Le seul stdin est celui provenant du fichier.

Ce que vous devez faire est d’offrir un moyen facultatif d’avoir la partie appropriée de votre script en lecture depuis un fichier, avec un switch comme

 --input=file.txt 

puis fournissez des invites interactives pour les autres parties.

Il est possible d’accepter à la fois l’entrée de canalisation et l’entrée utilisateur dans le même programme.

Le moyen le plus simple pour gérer cela est d’ subprocess module de subprocesssubprocess . Vous seriez en train d’exécuter le programme depuis votre programme Python. Les arguments vous permettent de configurer des canaux vers et / ou depuis le programme que vous exécutez.

C’est simple. C’est standard. Ça marche bien.

La même chose est vraie pour accepter un fichier via des arguments de programme. C’est simple. C’est standard. Ça marche bien. Comme avantage supplémentaire, dans Windows CMD.EXE / COMMAND.COM utilise automatiquement des fichiers temporaires pour les tuyaux. Vous ne tirez aucun avantage de faire quelque chose de plus compliqué en raison du fait que DOS / Windows ne supporte pas les vrais tuyaux.

Je sais que le code client mysql en ligne de commande accepte un mot de passe de l’utilisateur avant de traiter l’entrée La solution Linux (et probablement Mac OS X) à cela est probablement similaire à celle de Nemo. Si c’est le comportement que vous voulez vraiment et que vous ne vous souciez pas de Windows, c’est la solution à utiliser. (Pour Windows, vous devez utiliser quelque chose comme le package wconio. – http://newcenturycomputers.net/projects/wconio.html )

Il est possible d’avoir une entrée utilisateur et d’accepter une sortie redirigée vers un autre programme. Il existe trois types de fichiers: stdin, stdout et stderr. Vous pouvez écrire sur stderr même lorsque stdout est redirigé vers un fichier.