14.1 Pexpect简介
- Pexpect 是 Don Libes 的 Expect 语言的一个 Python 实现,是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其 自动交互的 Python 模块。
- Pexpect 的使用范围很广,可以用来实现与 ssh、ftp 、telnet 等程序的自动交互;可以用来自动复制软件安装包并在不同机器自动安装;还可以 用来实现软件测试中与命令行交互的自动化。
14.2 Pexpect 提供的 run() 函数
14.2.1 run() 的定义
- 函数 run 可以用来运行命令,其作用与 Python os 模块中 system() 函数相似。 run() 是通过 Pexpect类实现的。
- 如果命令的路径没有完全给出,则 run 会使用 which 命令尝试搜索命令的路径 。
14.2.2 使用 run()执行 svn 命令
- 与 os.system() 不同的是,使用 run() 可以方便地同时获得命令的输出结果与命令的退出状态 。
14.2.3 run() 的返回值
- command_out 中保存的就是 /bin 目录下的内容。
14.3 Pexpect 提供的 spawn() 类
14.3.1 使用 Pexpect 启动子程序
- spawn 的构造函数
- spawn是Pexpect模块主要的类,用以实现启动子程序,它有丰富的方法与子程序交互从而实现用户对子程序的控制。
- 它主要使用pty.fork() 生成子进程,并调用 exec() 系列函数执行 command 参数的内容。
- 当子程序需要参数时,还可以使用一个参数的列表
- 在构造函数中,maxread 属性指定了 Pexpect 对象试图从 tty 一次读取的最大字节数,它的默认值是2000字节 。
- 由于需要实现不断匹配子程序输出, searchwindowsize 指定了从输入缓冲区中进行模式匹配的位置,默认从开始匹配。
- logfile 参数指定了 Pexpect 产生的日志的记录位置。
- 还可以将日志指向标准输出
- 如果不需要记录向子程序输入的日志,只记录子程序的输出,可以使用
14.3.2 使用 Pexpect 控制子程序
为了控制子程序,等待子程序产生特定输出,做出特定的响应,可以使用expect 方法。
- expect() 定义
- 在参数中: pattern 可以是正则表达式, pexpect.EOF pexpect.TIMEOUT ,或者由这些元素组成的列表。
- 需要注意的是,当pattern 的类型是一个列表时,且子程序输出结果中不止一个被匹配成功,则匹配返回的结果是缓冲区中最先出现的那个元素,或者是列表中最左边的元素。
- 使用 timeout 可以指定等待结果的超时时间 ,该时间以秒为单位。
- 当超过预订时间时, expect 匹配到pexpect.TIMEOUT。
- 如果难以估算程序运行的时间,可以使用循环使其多次等待直至等待运行结束
- expect() 在执行中可能会抛出两种类型的异常分别是 EOF and TIMEOUF,其中 EOF 通常代表子程序的退出, TIMEOUT 代表在等待目标正则表达式中出现了超时。
- 如果难以估算程序运行的时间,可以使用循环使其多次等待直至等待运行结束。
- expect() 在执行中可能会抛出两种类型的异常分别是 EOF and TIMEOUF,其中 EOF 通常代表子程序的退出, TIMEOUT 代表在等待目标正则表达式中出现了超时。
- expect 不断从读入缓冲区中匹配目标正则表达式,当匹配结束时 pexpect 的before 成员中保存了缓冲区中匹配成功处之前的内容, pexpect 的 after 成员保存的是缓冲区中与目标正则表达式相匹配的内容。
- child.before 保存的就是在根目录下执行 ls 命令的结果。
- send 系列函数
- 这些方法用来向子程序发送命令,模拟输入命令的行为。
- 与 send() 不同的是sendline() 会额外输入一个回车符 ,更加适合用来模拟对子程序进行输入命令的操作。
- 当需要模拟发送 “Ctrl+c” 的行为时,还可以使用 sendcontrol() 发送控制字符。
- 发送 ctrl+c
- 由于 send() 系列函数向子程序发送的命令会在终端显示,所以也会在子程序的输入缓冲区中出现,因此不建议使用 expect 匹配最近一次 sendline() 中包含的字符。
- 否则可能会在造成不希望的匹配结果。
- interact() 定义
- Pexpect还可以调用interact() 让出控制权,用户可以继续当前的会话控制子程序。
- 用户可以敲入特定的退出字符跳出,其默认值为“^]” 。
14.4 Paramiko
- paramiko是基于Python实现的SSH2远程安全连接,支持认证及密钥方式。可以实现远程命令执行、文件传输、中间SSH代理等功能,相对于Pexpect,封装的层次更高,更贴近SSH协议的功能
- paramiko包含两个核心组件
- 一个为SSHClient类
- 另一个为SFTPClient类。
14.4.1 SSHClient类
- SSHClient类是SSH服务会话的高级表示,该类封装了传输(transport)、通道(channel)及SFTPClient的校验、建立的方法,通常用于执行远程命令。
- connect方法
- 参数说明:
- hostname(str类型),连接的目标主机地址;
- port(int类型),连接目标主机的端口,默认为22;
- username(str类型),校验的用户名(默认为当前的本地用户名);
- password(str类型),密码用于身份校验或解锁私钥;
- pkey(Pkey类型),私钥方式用于身份验证;
- key_filename(str or list(str)类型),一个文件名或文件名列表,用于私钥的身份验证;
- timeout(float类型),一个可选的超时时间(以秒为单位)的TCP连接;
- allow_agent(bool类型),设置为False时用于禁用连接到SSH代理;
- look_for_keys(bool类型),设置为False时用于来禁用在~/.ssh中搜索私钥文件;
- compress(bool类型),设置为True时打开压缩。
- exec_command方法
- 远程命令执行方法,该命令的输入与输出流为标准输入(stdin)、输出(stdout)、错误(stderr)的Python文件对像。
- 参数说明:
- command(str类型),执行的命令串;
- bufsize(int类型),文件缓冲区大小,默认为-1(不限制)
- load_system_host_keys方法
- 加载本地公钥校验文件,默认为~/.ssh/known_host,非默认路径需要手工指定。
- ~/.ssh/known_hosts的作用:当ssh会把你每个你访问过计算机的公钥(public key)都记录在~/.ssh/known_hosts。
- 当下次访问相同计算机时,OpenSSH会核对公钥。
- 如果公钥不同,OpenSSH会发出警告
- 参数说明:
- filename(str类型),指定远程主机公钥记录文件。
- set_missing_host_policy方法
- 设置连接的远程主机没有主机密钥或HostKeys对象时的策略,目前支持三种,分别是AutoAddPolicy、RejectPolicy(默认)、WarningPolicy,仅限用于SSHClient类。
- AutoAddPolicy,目标添加主机名及主机密钥到本地HostKeys对象,并将其保存,不依赖load_system_host_keys()的配置,即~/.ssh/hnown_hosts不存在也不产生影响;
- RejectPolicy,自动拒绝未知的主机名和密钥,依赖load_system_host_keys()的配置;
- WarningPolicy,用于记录一个未知的主机密钥的Python警告,并接收它,功能上AutoAddPolicy相似,但未知主机会有告警。
14.4.2 SFTPClient类
- SFTPClient作为一个SFTP客户端对象,根据SSH传输协议的sftp会话,实现远程文件操作,比如文件上传、下载、权限、状态等操作。
- from_transport方法
- 参数说明
- t(transport),一个已通过验证的传输对象。
- put方法
- 参数说明:
- localpath(str类型),需上传的本地文件(源);
- remotepath(str类型),远程路径(目标);
- callback(funcation(int,int)),获取已接收的字节数及总传输字节数,以便回调函数调用,默认为None;
- confirm(bool类型),文件上传完毕后是否调用stat()方法,以便确认文件的大小。
- get方法
- 参数说明:
- remotepath(str类型),需要下载的远程文件(源);
- callback(funcation(int,int)),获取已接收的字节数及总和传输字节数,以便回调函数调用,默认为None.
- 其它方法
- SFTPClient类其它常用方法说明:
- mkdir,在SFTP服务端创建目录,如sftp.mkdir("/home/userdir",mode=0777),默认模式是0777(八进制),在某些系统上,mode被忽略。在使用它的地方,当前的umask值首先被屏蔽掉。
- remove,删除SFTP服务端指定目录,如sftp.remove("/home/userdir")。
- rename,重命名SFTP服务端文件或目录,如sftp.rename("/home/test.sh","/home/testfile.sh")
- stat,获取远程SFTP服务端指定文件信息,如sftp.stat("/home/testfile.sh")。
- listdir,获取远程SFTP服务端指定目录列表,以Python的列表(List)形式返回,如sftp.listdir("/home")。
14.4.3 实验
In:
pip install paramiko
out:
Requirement already satisfied: paramiko in d:\programdata\anaconda3\lib\site-packages (2.7.1)
Requirement already satisfied: cryptography>=2.5 in d:\programdata\anaconda3\lib\site-packages (from paramiko) (2.7)
Requirement already satisfied: pynacl>=1.0.1 in d:\programdata\anaconda3\lib\site-packages (from paramiko) (1.4.0)
Requirement already satisfied: bcrypt>=3.1.3 in d:\programdata\anaconda3\lib\site-packages (from paramiko) (3.1.7)
Requirement already satisfied: cffi!=1.11.3,>=1.8 in d:\programdata\anaconda3\lib\site-packages (from cryptography>=2.5->paramiko) (1.12.3)
Requirement already satisfied: asn1crypto>=0.21.0 in d:\programdata\anaconda3\lib\site-packages (from cryptography>=2.5->paramiko) (1.0.1)
Requirement already satisfied: six>=1.4.1 in d:\programdata\anaconda3\lib\site-packages (from cryptography>=2.5->paramiko) (1.12.0)
Requirement already satisfied: pycparser in d:\programdata\anaconda3\lib\site-packages (from cffi!=1.11.3,>=1.8->cryptography>=2.5->paramiko) (2.19)
Note: you may need to restart the kernel to use updated packages.
In:
import paramiko
主机:xxx.xxx.xxx.xxx
用户:student
密码:xxxxxx
端口:xx
In:
sshc = paramiko.SSHClient()
In:
sshc.set_missing_host_key_policy(paramiko.AutoAddPolicy())
In:
sshc.connect(hostname='192.168.199.175',port=22,username='student',
password='123456')
In:
stdin,stdout,stderr = sshc.exec_command('df -m')
In:
print(stdout.read().decode('utf-8'))
out:
Filesystem 1M-blocks Used Available Use% Mounted on
/dev/sda1 32354 6759 23946 23% /
tmpfs 1917 1 1917 1% /dev/shm