2016-05-22 5 views
4

私が意図したとおりに動作する次のコードを持っている:`stdin = sys.stdin`を` stdin = PIPE`でどのように再現するのですか?

私は対話的にはbashを使用することができます
from subprocess import Popen 

process = Popen(
    ["/bin/bash"], 
    stdin=sys.stdin, 
    stdout=sys.stdout, 
    stderr=sys.stderr, 
) 
process.wait() 

、タブの作品など

しかし、私は標準入力に送るかを制御したいので、私は」次のように動作します:

import os 
import sys 
from subprocess import Popen, PIPE 
from select import select 

process = Popen(
    ["/bin/bash"], 
    stdin=PIPE, 
    stdout=sys.stdout, 
    stderr=sys.stderr, 
) 

while True: 
    if process.poll() is not None: 
     break 

    r, _, _ = select([sys.stdin], [], []) 

    if sys.stdin in r: 
     stdin = os.read(sys.stdin.fileno(), 1024) 
     # Do w/e I want with stdin 
     os.write(process.stdin.fileno(), stdin) 

process.wait() 

しかし、動作は同じではありません。私は別のアプローチ(PTYを経由する)しようとしました:

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

master, slave = os.openpty() 
stdin = sys.stdin.fileno() 

try: 
    tty.setraw(master) 
    ttyname = os.ttyname(slave) 

    def _preexec(): 
     os.setsid() 
     open(ttyname, "r+") 

    process = Popen(
     args=["/bin/bash"], 
     preexec_fn=_preexec, 
     stdin=slave, 
     stdout=sys.stdout, 
     stderr=sys.stderr, 
     close_fds=True, 
    ) 

    while True: 
     if process.poll() is not None: 
      break 

     r, _, _ = select([sys.stdin], [], []) 

     if sys.stdin in r: 
      os.write(master, os.read(stdin, 1024)) 
finally: 
    os.close(master) 
    os.close(slave) 

をや行動は動作しません、まだタブを除いて、かなり近いです。さて、タブは適切に送信されますが、私の端末はbashで完了しても完了を表示しません。矢印はまた、歴史の代わりに^[[Aを表示します。

+0

あなたは(通常は)あなたとあなたの最初のコード例に取って代わることができることを知っていますか? 'pty.spawn(['/ bin/bash']、master_read、stdin_read)'( '-i'、' -l'などを渡す必要がありますか)を直接使用することもできます? – jfs

答えて

1

私が必要としていたのは、sys.stdoutを生のままに設定していたことでした。私はまた、3つの事が分かった:私はsys.stdout

  • subprocess.Popen上で、端末の設定を復元する必要が

    • を私_preexec機能がやっているんstart_new_session引数を持っています。
    • select.selectは、4番目の引数を受け取ります。これは、タイムアウトしてから放棄されます。それは、終了後にselectループに詰まることを避けることができます。

    最終的なコードは: `subprocess.call([ '/ binに/ bashの'])`:

    import os 
    import sys 
    import tty 
    import termios 
    import select 
    import subprocess 
    
    master, slave = os.openpty() 
    stdin = sys.stdin.fileno() 
    
    try: 
        old_settings = termios.tcgetattr(sys.stdout) 
        tty.setraw(sys.stdout) 
    
        process = subprocess.Popen(
         args=["/bin/bash"], 
         stdin=slave, 
         stdout=sys.stdout, 
         stderr=sys.stderr, 
         close_fds=True, 
         start_new_session=True, 
        ) 
    
        while True: 
         if process.poll() is not None: 
          break 
    
         r, _, _ = select.select([sys.stdin], [], [], 0.2) 
    
         if sys.stdin in r: 
          os.write(master, os.read(stdin, 1024)) 
    finally: 
        termios.tcsetattr(sys.stdout, termios.TCSADRAIN, old_settings) 
        os.close(master) 
        os.close(slave) 
    
  • 関連する問題