2012-03-12 22 views
11

Python'un subprocess modülüyle uğraşıyorum ve python'dan bash ile etkileşimli bir oturum yapmak istedim. Bir terminal emülatöründe yaptığım gibi Python'dan bash output/write komutlarını okumak istiyorum. Bir kod örneği daha iyi açıklıyor sanırım:Python'dan bash ile etkileşim

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

(. Açıkçası, bu şekilde çalışmıyor) bu mümkün gibi bir şey ve nasıl mı?

Çok teşekkürler

cevap

10

Dene:

import subprocess 

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

print stdout 

Sen Stdin, stdout ve stderr hakkında daha fazla okumak zorunda. Bu, iyi ders benziyor: http://www.doughellmann.com/PyMOTW/subprocess/

DÜZENLEME:

Başka bir örnek:

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

İlk .communicate() çağrısı iyi çalışıyor, ancak yeniden iletişim kurmaya çalışırsam bu olur: 'ValueError: Kapalı dosyada G/Ç işlemi. Onu devam ettirmenin bir yolu var mı? – justinas

+0

İkinci örneğe bakın. – Adam

+0

1- İlk kod örneği stdout = subprocess.check_output (['ls', '-lash']) 'şeklinde yazılabilir. Bir 'bash 'komutunu çalıştırmak için , check_output (" bazı && komut $ ( jfs

10

pexpect görevin bu tür için özel olarak tasarlanmıştır. Bu saf Python ve saygıdeğer TCL aracı olan expect'dan esinlenmiştir. Bu örnekle

+0

Teşekkürler, iyi bir araç gibi görünüyor, ama bunu pexpect olmadan başarmanın herhangi bir yolu var mı? – justinas

3

etkileşimli bash işlemi uçbirimlerden etkileşim bekliyor. Sözde terminal oluşturmak için os.openpty() öğesini kullanın. Bu, stdin, stdout ve stderr dosyalarını açmak için kullanabileceğiniz bir slave_fd dosya tanıtıcısını döndürür. Daha sonra işleminizle etkileşimde bulunmak için master_fd'den yazabilir ve okuyabilirsiniz. Karmaşık bir etkileşim bile yapıyorsanız, kilitlenmediğinizden emin olmak için seçim modülünü de kullanmak isteyeceğinizi unutmayın.

3

* nix kabuk ve python arasındaki etkileşimi kolaylaştırmak için bir modül yazdım.

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 '' 

Kontrol dışarı github kıyısında bütün şeyler: https://github.com/jerryzhujian9/ez.py/blob/master/ez/easyshell.py

+0

şimdi pip ile yükleyebilirsiniz: pip install ez –

1

Kullanım benim diğer yanıtında bu örnek: https://stackoverflow.com/a/43012138/3555925

Böyle bir cevap daha fazla ayrıntı elde edebilirsiniz.

#!/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)