2012-03-12 16 views
11

से बैश के साथ बातचीत करना मैं पाइथन के subprocess मॉड्यूल के साथ खेल रहा हूं और मैं अजगर से बैश के साथ "इंटरैक्टिव सत्र" करना चाहता था। मैं पाइथन से बैश आउटपुट/लिखने के आदेशों को पढ़ने में सक्षम होना चाहता हूं जैसे कि मैं टर्मिनल एमुलेटर पर करता हूं। मुझे लगता है कि एक कोड उदाहरण बेहतर बताते हैं:पायथन

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

(। जाहिर है, इसे उस तरह से काम नहीं करता है) यह संभव तरह कुछ, और कैसे है?

धन्यवाद एक बहुत

उत्तर

10

प्रयास करें:

import subprocess 

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

print stdout 

आप stdin, stdout और stderr के बारे में अधिक पढ़ने के लिए। यह अच्छा व्याख्यान की तरह दिखता है: http://www.doughellmann.com/PyMOTW/subprocess/

संपादित करें:

एक और उदाहरण:

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

पहला .communicate() कॉल अच्छी तरह से काम करता है, लेकिन अगर मैं फिर से संवाद करने की कोशिश करता हूं, तो ऐसा होता है: 'ValueError: I/O ऑपरेशन बंद फ़ाइल पर। क्या इसे चलाने के लिए कोई रास्ता है? – justinas

+0

दूसरा उदाहरण देखें। – Adam

+0

1- पहला कोड उदाहरण 'stdout = subprocess.check_output ([' ls ',' -lash '] के रूप में लिखा जा सकता है) '। 'Bash' कमांड चलाने के लिए, आप 'check_output (" कुछ && कमांड $ ( jfs

10

pexpect काम के इस प्रकार के लिए विशेष रूप से डिजाइन किया गया है। यह शुद्ध पायथन है और यह expect, आदरणीय टीसीएल उपकरण से प्रेरित है।

इस उदाहरण के साथ
+0

धन्यवाद, एक अच्छा उपकरण की तरह लगता है, लेकिन क्या यह बिना किसी परेशानी के इसे प्राप्त करने का कोई तरीका है? – justinas

3

एक इंटरैक्टिव बैश प्रक्रिया एक tty के साथ बातचीत किए जाने की उम्मीद है। एक छद्म टर्मिनल बनाने के लिए, os.openpty() का उपयोग करें। यह एक गुलाम_एफडी फ़ाइल डिस्क्रिप्टर वापस करेगा जो आप stdin, stdout, और stderr के लिए फ़ाइलों को खोलने के लिए उपयोग कर सकते हैं। फिर आप अपनी प्रक्रिया के साथ बातचीत करने के लिए master_fd से लिख सकते हैं और पढ़ सकते हैं। ध्यान दें कि यदि आप हल्के जटिल जटिलता भी कर रहे हैं, तो आप यह सुनिश्चित करने के लिए चुनिंदा मॉड्यूल का भी उपयोग करना चाहेंगे कि आप डेडलॉक नहीं करते हैं।

3

मैंने * निक्स शैल और पायथन के बीच बातचीत को सुविधाजनक बनाने के लिए एक मॉड्यूल लिखा था।

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

चेक बाहर GitHub पर पूरे सामान: https://github.com/jerryzhujian9/ez.py/blob/master/ez/easyshell.py

+0

अब आप पाइप के माध्यम से स्थापित कर सकते हैं: पाइप इंस्टॉल ez –

1

मेरे अन्य जवाब में इस उदाहरण का उपयोग करें: https://stackoverflow.com/a/43012138/3555925

आपको लगता है कि जवाब में अधिक जानकारी प्राप्त कर सकते हैं।

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