2017-06-14 2 views
1

J'ai un script python qui doit afficher certaines valeurs dans stdin et copier une autre chaîne dans le presse-papiers. J'utilise le module subprocess pour exécuter l'utilitaire xclip par Popen quelque chose comme ceci:Le script Python utilisant un sous-processus et xclip se bloque s'il est redirigé vers bash

# clip.py 
import subprocess 
from subprocess import Popen 

print('PRINT_ME') 
p1 = Popen(['xclip', '-selection', 'clipboard'], stdin=subprocess.PIPE) 
p1.communicate(input=('PASTE_ME'.encode())) 

Le script fonctionne comme prévu: PRINT_ME se retrouve dans bash et PASTE_ME est disponible pour coller, et retourne imediatly.

Un problème apparaît lorsque la sortie du script est redirigée vers une autre commande. Supposons que l'on veut rediriger vers un fichier et stdin en utilisant tee:

$ python clip.py|tee file.txt 

Le programme fonctionne comme on le suppose, mais pas de retour, à savoir shell ne donnent pas la main.

Comment cela peut-il être réparer?

Quelques informations importantes: l'utilitaire xclipfourches lui-même (pour faire face à la mise en œuvre de planchettes sur X) le maintien de la chaîne avaliable à copier, lorsqu'il est utilisé dans la coquille, il retourne immédiatement (il fourches à fond). Il semble que le shell attache à la fois clip.py et xclip stdin/stdout à tee.
Si xclip -selection clipboard est trouvé en utilisant ps u et a tué la commande retourne. Je utilise Python 3.4.
Merci

Répondre

0

Il est pas dû à bifurquer de xclip, il est dû à la façon dont Python gère Popen.wait() (qui est appelé avec votre appel à communicate()) - du point de vue Python xclip (silencieux par défaut) n'a pas fermé son flux il attend ... Voilà pourquoi tout fonctionne sauf pour Python passe devant votre ligne p1.communicate() lorsque vous redirigez ses cours d'eau pour quelque chose d'autre (tee dans ce cas) - il attend tout de son fichier poignées pour fermer ...

Vous pouvez ouvrez et fermez manuellement vos flux, ou configurez simplement xclip pour filtrer STDIN vers STDOUT et garder Python libre y:

import subprocess 

p1 = subprocess.Popen(['xclip', '-selection', 'clipboard', '-f'], stdin=subprocess.PIPE) 
p1.communicate(input=('PASTE_ME'.encode())) 
# etc. 

N'a pas testé, mais cela devrait fonctionner. Si vous ne voulez pas que xclip imprime votre STDOUT actuel, il suffit de le rediriger lors de l'instanciation de subprocess.Popen() à None (ou de subprocess.DEVNULL pour Python 3.x) ou de toute autre poignée de flux que vous souhaitez.

+0

Merci pour votre réponse, les deux façons ont bien fonctionné! J'ai testé diverses modifications et trouvé intéressant que tout code après 'p1.communicate' (dans le code défectueux original) est exécuté, le programme s'arrête pour quitter. Et à partir des deux solutions proposées qui est plus «pythonique» et sans effets secondaires? – mglart

+0

Vous avez raison, je me suis mal exprimé - Popen ouvre un FH pour STDOUT de xclip (et le lie au STDOUT actuel) et comme 'xclip' ne ferme jamais le flux, il continue d'attendre à la fin pour qu'il puisse quitter sous-processus. Quant à _Pythonic_ - c'est un terme illusoire qui signifie différentes choses pour différentes personnes, mais la plupart des gens sont d'accord pour dire que l'approche KISS est la quintessence d'être _Pythonic_ - donc, sauf si vous avez besoin de faire quelque chose avec STDIN/STDOUT, Popen.communiquez() 'et sauvegardez vous-même des problèmes quand' xclip' vous permet déjà de le configurer pour jouer correctement avec Python. – zwer