2

我有一个从某个设备获取输入流的 linux 应用程序。该输入应定向到 shell 进程,以便它向用户模拟标准 shell。到目前为止,我已经通过创建一个运行“/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() 并将 slave 设置为标准输入,但这也不起作用。应该怎么做?

更新:我按照建议使用了 -i 参数。现在我有一个问题,一旦我使用 Popen 并按 ENTER,python shell 就会移动到后台,如下所示:

>>> 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. 使用无缓冲文件(在 bufsize 中传递 0)打开 pty 设备。

这是有效的代码:

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