2012-03-12 16 views
11

He estado jugando con el módulo de Python subprocess y quería hacer una "sesión interactiva" con la fiesta del pitón. Quiero poder leer los comandos bash de salida/escritura de Python, tal como lo hago en un emulador de terminal. Creo que un ejemplo de código lo explica mejor:Interactuar con fiesta de pitón

>>> proc = subprocess.Popen(['/bin/bash']) 
>>> proc.communicate() 
('[email protected]:~/','') 
>>> proc.communicate('ls\n') 
('file1 file2 file3','') 

(., Obviamente, no funciona de esa manera) es algo como esto sea posible, y cómo?

Muchas gracias

Respuesta

10

intento con este ejemplo:

import subprocess 

proc = subprocess.Popen(['/bin/bash'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) 
stdout = proc.communicate('ls -lash') 

print stdout 

Hay que leer más sobre stdin, stdout y stderr. Esto parece buena conferencia: http://www.doughellmann.com/PyMOTW/subprocess/

EDIT:

Otro ejemplo:

>>> process = subprocess.Popen(['/bin/bash'], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE) 
>>> process.stdin.write('echo it works!\n') 
>>> process.stdout.readline() 
'it works!\n' 
>>> process.stdin.write('date\n') 
>>> process.stdout.readline() 
'wto, 13 mar 2012, 17:25:35 CET\n' 
>>> 
+1

La primera llamada .communicate() funciona bien, pero si trato de comunicarme de nuevo, sucede esto: 'ValueError: operación de E/S en archivo cerrado'. ¿Hay alguna forma de mantenerlo funcionando? – justinas

+0

Mira el segundo ejemplo. – Adam

+0

1- El primer ejemplo de código se puede escribir como 'stdout = subprocess.check_output (['ls', '-lash'])'. Para ejecutar un comando 'bash', puede' check_output ("some && command $ ( jfs

10

pexpect está diseñado específicamente para este tipo de tareas. Es pura Python y está inspirada en expect, la venerable herramienta TCL.

+0

Gracias, parece una buena herramienta, pero ¿hay alguna manera de lograr esto sin pexpect? – justinas

3

Un proceso fiesta interactiva espera estar interactuando con un TTY. Para crear un pseudo-terminal, use os.openpty(). Esto devolverá un descriptor de archivo slave_fd que puede usar para abrir archivos para stdin, stdout y stderr. Luego puede escribir y leer desde master_fd para interactuar con su proceso. Tenga en cuenta que si está haciendo una interacción medianamente compleja, también querrá utilizar el módulo de selección para asegurarse de que no se estanca.

3

Escribí un módulo para facilitar la interacción entre * nix shell y python.

def execute(cmd): 
if not _DEBUG_MODE: 
    ## Use bash; the default is sh 
    print 'Output of command ' + cmd + ' :' 
    subprocess.call(cmd, shell=True, executable='/bin/bash') 
    print '' 
else: 
    print 'The command is ' + cmd 
    print '' 

Salida toda la materia en github: https://github.com/jerryzhujian9/ez.py/blob/master/ez/easyshell.py

+0

ahora puede instalarlo a través de pip: pip install ez –

1

Uso este ejemplo en mi otra respuesta: https://stackoverflow.com/a/43012138/3555925

Puede obtener más detalles en esa respuesta.

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

import os 
import sys 
import select 
import termios 
import tty 
import pty 
from subprocess import Popen 

command = 'bash' 
# command = 'docker run -it --rm centos /bin/bash'.split() 

# save original tty setting then set it to raw mode 
old_tty = termios.tcgetattr(sys.stdin) 
tty.setraw(sys.stdin.fileno()) 

# open pseudo-terminal to interact with subprocess 
master_fd, slave_fd = pty.openpty() 

# use os.setsid() make it run in a new process group, or bash job control will not be enabled 
p = Popen(command, 
      preexec_fn=os.setsid, 
      stdin=slave_fd, 
      stdout=slave_fd, 
      stderr=slave_fd, 
      universal_newlines=True) 

while p.poll() is None: 
    r, w, e = select.select([sys.stdin, master_fd], [], []) 
    if sys.stdin in r: 
     d = os.read(sys.stdin.fileno(), 10240) 
     os.write(master_fd, d) 
    elif master_fd in r: 
     o = os.read(master_fd, 10240) 
     if o: 
      os.write(sys.stdout.fileno(), o) 

# restore tty settings back 
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty) 
Cuestiones relacionadas