使用os.forkpty()创建伪终端以SSH连接远程服务器并进行通信

6 投票
2 回答
6694 浏览
提问于 2025-04-17 00:15

我正在尝试写一个Python脚本,这个脚本可以通过SSH连接到远程服务器,并且能够从Python客户端执行一些简单的命令,比如ls(列出文件)和cd(切换目录)。但是,在成功连接到服务器后,我无法读取伪终端的输出。有没有人能帮我一下,让我可以在服务器上执行一些命令。

以下是示例代码:

#!/usr/bin/python2.6
import os,sys,time,thread
pid,fd = os.forkpty()
if pid == 0:
    os.execv('/usr/bin/ssh',['/usr/bin/ssh','user@host',])
    sys.exit(0)
else:
    output = os.read(fd,1024)
    print output
    data = output
    os.write(fd,'password\n')
    time.sleep(1)
    output = os.read(fd,1024)
    print output
    os.write(fd,'ls\n')
    output = os.read(fd,1024)
    print output

示例输出:

user@host's password: 

Last login: Wed Aug 24 03:16:57 2011 from 1x.x.x.xxxx

-bash: ulimit: open files: cannot modify limit: Operation not permitted
host: /home/user>ls

2 个回答

2

正如之前提到的,最好使用公钥。因为我通常都是这样做的,所以我对你的程序进行了修改,使它在这里可以正常工作。

#!/usr/bin/python2.6
import os,sys,time,thread
pid,fd = os.forkpty()
if pid == 0:
    os.execv('/usr/bin/ssh',['/usr/bin/ssh','localhost',])
    sys.exit(0)
else:
    output = os.read(fd,1024)
    print output
    os.write(fd,'ls\n')
    time.sleep(1) # this is new!
    output = os.read(fd,1024)
    print output

通过添加 sleep(1),我给远程主机(或者在我的情况下,不是那么远的主机)留出时间来处理 ls 命令并生成输出。

如果你发送 ls 命令后立刻读取,你只会得到当前存在的内容。也许你应该在一个循环中读取一下。

或者你可以这样做:

import subprocess
sp = subprocess.Popen(("ssh", "localhost", "ls"), stdout=subprocess.PIPE)
print sp.stdout.read()
3

我建议你试试一个叫做pexpect的模块,它就是为了处理这种情况而设计的(通过伪终端与其他应用程序进行交互)。还有一个叫Fabric的工具,它更抽象一些,主要用于自动化远程服务器上的系统管理任务,通常是通过SSH来实现。

pexpect: http://pypi.python.org/pypi/pexpect/

Fabric: http://docs.fabfile.org/en/1.11/

撰写回答