2010-09-22 32 views
0

Je le code python suivant:Utilisation de descripteurs de fichiers pour communiquer entre les processus

import pty 
import subprocess 
os=subprocess.os 
from subprocess import PIPE 
import time 
import resource 

pipe=subprocess.Popen(["cat"], stdin=PIPE, stdout=PIPE, stderr=PIPE, \ 
         close_fds=True) 
skip=[f.fileno() for f in (pipe.stdin, pipe.stdout, pipe.stderr)] 
pid, child_fd = pty.fork() 
if(pid==0): 
    max_fd=resource.getrlimit(resource.RLIMIT_NOFILE)[0] 
    fd=3 
    while fd<max_fd: 
     if(fd not in skip): 
      try: 
       os.close(fd) 
      except OSError: 
       pass 
      fd+=1 
     enviroment=os.environ.copy() 
     enviroment.update({"FD": str(pipe.stdin.fileno())}) 
     os.execvpe("zsh", ["-i", "-s"], enviroment) 
else: 
    os.write(child_fd, "echo a >&$FD\n") 
    time.sleep(1) 
    print pipe.stdout.read(2) 

Comment puis-je réécrire pour qu'il n'utilisera Popen et cat? J'ai besoin d'un moyen de transmettre les données d'une fonction shell exécutée dans le shell interactif qui ne se mélange pas avec les données créées par d'autres fonctions (donc je ne peux pas utiliser stdout ou stderr).

+0

Pourquoi ne pouvez-vous pas juste "subprocess.Popen()" le shell directement? – llasram

+0

@llasram parce que j'ai besoin d'un shell interactif pour capturer les arguments passés à l'achèvement builtin 'compadd'. Pas de tty - pas d'interaction - pas de complétion. – ZyX

+0

Je ne suis pas tout à fait la suite ... Pourriez-vous donner un exemple concret? – llasram

Répondre

1

Ok, je pense que j'ai une idée de votre question maintenant et que vous pouvez voir deux approches différentes.

Si vous voulez absolument fournir la coquille dans le processus de l'enfant avec un descripteur de fichier déjà ouvert, vous pouvez remplacer le Popen() de cat avec un appel à os.pipe(). Cela vous donnera une paire connectée de descripteurs de fichiers réels (pas d'objets Python file). Tout ce qui est écrit dans le second descripteur de fichier peut être lu à partir du premier, en remplaçant votre cat -pipe. (Bien que "cat-pipe" soit amusant à dire ...). Une paire de socket (socket.socketpair()) peut également être utilisée pour atteindre la même fin si vous avez besoin d'une paire bidirectionnelle. Alternativement, vous pourriez vous simplifier la vie encore plus en utilisant un tube nommé (alias FIFO). Si vous n'êtes pas familier avec l'installation, un canal nommé est un canal unidirectionnel situé dans l'espace de noms du système de fichiers. La fonction os.mkfifo() va créer le canal sur le système de fichiers. Vous pouvez ensuite ouvrir le canal pour lire dans votre processus principal et l'ouvrir pour l'écriture/sortie directe à partir de votre processus enfant shell. Cela devrait simplifier votre code et ouvrir l'option d'utiliser une bibliothèque existante comme Pexpect pour interagir avec le shell.

+0

Merci, je n'utilisais pas 'mkfifo' car il crée de nouveaux fichiers. Et j'ai essayé d'utiliser 'os.pipe()', mais j'ai échoué à deviner que je devrais utiliser la seconde fd dans le script enfant et d'abord dans le parent. L'idée d'utiliser 'pty.fork' est venue après l'examen des codes source de pexpect. – ZyX