2

デバイスから入力ストリームを取得する Linux アプリケーションがあります。その入力は、ユーザーに対して標準シェルをエミュレートできるように、シェル プロセスに送信する必要があります。これまでのところ、「/bin/sh」を実行するプロセスを作成し、その入力、出力、および stderr を次のようにリダイレクトしました。

import subprocess

p = subprocess.Popen(shell=False, args=['/bin/sh'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
_make_nonblocking(p.stdout) # sets O_NONBLOCK
_make_nonblocking(p.stderr)

pass コマンドだけを実行すると、すべてが機能します。

p.stdin.write('pwd\n')
p.stdout.read()
'/home/dave\n'

自動補完のために、私は書いてみました:

p.stdin.write('ls s\t')
p.stdout.read()
IOError: [Errno 11] Resource temporarily unavailable

可能な補完のリストを取得することを期待していますが、標準入力に '\n' を入れるまで何も起こりません。(また、stderr には何も待機していませんでした)。

telnetd コードを調べたところ、pty の使用が見られました。pty.openpty() を使用してスレーブを標準入力に設定しようとしましたが、それも機能しませんでした。それはどのように行われるべきですか?

更新: -i パラメーターを提案どおりに使用しました。Popen を使用して ENTER を押すと、Python シェルが次のようにバックグラウンドに移動するという問題があります。

>>> p = subprocess.Popen(shell=False, args=['/bin/sh', '-i'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> <ENTER>
[1]+ Stopped                ipython
$ 
4

2 に答える 2

5

bashオートコンプリートを使用すると、インタラクティブ モードでのみ機能します。

-i        If the -i option is present, the shell is interactive.

これにより、プロンプトの表示や通常のすべてのものを含む、適切なエミュレーションが行われます。

于 2012-08-27T17:05:20.563 に答える
3

最終的にすべての問題を完全に解決するには、いくつかのことをしなければなりませんでした。

  1. pty デバイスを構成します (python で pty モジュールを使用)。
  2. termios (エコー、シグナル処理など) を使用して適切なフラグを設定します。
  3. 新しいセッションを開始します(信号が元のプロセスを伝播しないように)。
  4. バッファリングされていないファイルを使用して pty デバイスを開きます (bufsize に 0 を渡します)。

これは機能するコードです:

def prepare():
    os.setsid() # start a new detached session
    tty.setcbreak(sys.stdin) # set standard input to cbreak mode
    old = termios.tcgetattr(sys.stdin)
    old[0] |= termios.BRKINT # transforms break to SIGINT
    old[3] &= termios.ICANON # non-canonical mode
    old[3] |= termios.ECHO | termios.ISIG # set echo and signal characters handling
    cc = old[6]
    # make input unbuffered
    cc[termios.VMIN] = 1
    cc[termios.VTIME] = 0
    termios.tcsetattr(sys.stdin, termios.TCSANOW, old)

master, slave = pty.openpty()
master = os.fdopen(master, 'rb+wb', 0) # open file in an unbuffered mode
_make_non_blocking(master)

prog = subprocess.Popen(shell=False, args=['/bin/sh', '-i'], stdin=slave, stdout=slave, stderr=subprocess.STDOUT, preexec_fn=prepare)
于 2012-09-02T11:04:33.630 に答える