python3 -- pexpect 自动化交互式控制台命令行

26 篇文章 2 订阅
10 篇文章 0 订阅

python3 – pexpect
此函数库一般用于自动化交互式控制台命令行

1.首先安装 pexpect

[root@192 python]# python3 -m pip install pexpect
WARNING: Running pip install with root privileges is generally not a good idea. Try `__main__.py install --user` instead.
Collecting pexpect
  Downloading https://files.pythonhosted.org/packages/39/7b/88dbb785881c28a102619d46423cb853b46dbccc70d3ac362d99773a78ce/pexpect-4.8.0-py2.py3-none-any.whl (59kB)
    100% |████████████████████████████████| 61kB 672kB/s
Collecting ptyprocess>=0.5 (from pexpect)
  Downloading https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl
Installing collected packages: ptyprocess, pexpect
Successfully installed pexpect-4.8.0 ptyprocess-0.7.0
[root@192 python]# python3
Python 3.6.8 (default, Nov 16 2020, 16:55:22)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pexpect
>>>

2.简单应用
先看一个简单的命令

#使用spawn创建一个子进程,执行ls -la命令
child = pexpect.spawn('ls -la')
#expect用来等待特定的标志,如pexpect.EOF代表子进程已结束
child.expect(pexpect.EOF)
#输出ls -la的输出结果
print(child.before)

输出效果:

b'total 12\r\ndrwxr-xr-x  2 root root 4096 Jun 10 06:56 .\r\ndrwxr-xr-x 21 pi   pi   4096 Jun 10 06:55 ..\r\n-rwxrwxrwx  1 root root  305 Jun 10 07:23 0.py\r\n'

比较乱,是一个字节序列 b’*’ ,我们可以进一步用decode(‘utf-8’)处理一下,如下:

print(child.before.decode('utf-8'))
#得到输出:
total 12
drwxr-xr-x  2 root root 4096 Jun 10 06:56 .
drwxr-xr-x 21 pi   pi   4096 Jun 10 06:55 ..
-rwxrwxrwx  1 root root  334 Jun 10 07:26 0.py

3.管控执行结果,等待期望的值
上文有提到,我们可以利用pexpect()来定义一个或多个期望的值,程序会监控子程序执行进程,直到等到期望值或者子程序执行完毕再继续往下走
所以我们可以使用此特性去监控一些特定的执行结果,假设我需要监控一个文件status.txt里的内容, pass/fail两种状态,两种状态分别对应不同的处理方式,代码如下:

#首先在status.txt中记录pass
import pexpect
import sys

child = pexpect.spawn('cat status.txt')
rec=child.expect(['pass','fail'])
if rec == 0:
  print("pass")
elif rec == 1:
  print("fail")
  sys.exit()
else:
  sys.exit()

输出结果:

pass

rec结果是返回的列表内的元素索引,如这里,匹配到了pass,所以返回了0.注意这里只能匹配一次,先匹配到谁,就先输出谁。

3,timeout设定
我们可以对于命令的响应设定timeout,以免cmd未相应导致脚本一直等待,影响执行,如果不做设定,默认是30s超时

import pexpect
import sys

child = pexpect.spawn('ping 192.168.9.102')
try:
    rec = child.expect(['icmp_seq=15'], timeout=10, searchwindowsize=10000)
    if rec == 0:
        print('success')
except pexpect.TIMEOUT:
    print('timeout')

如此例子,我们使用ping命令去做一个持续长期的cmd执行,抓寻关键字icmp_seq=15,正常情况下在15s的时候才能打印到此关键字,但是我设定了timeout 10 s, 所以他会在10s时停止
但我使用了try except,并且在其超时 pexpect.TIMEOUT时,打印timeout.避免了程序直接退出,这里我们还能做其他的操作
所以程序执行结果会输出 “timeout”
这里引入了一个新的参数searchwindowsize=10000,代表缓存区的大小,单位为字节,默认为2000.当然,这个值设定太大可能会影响程序执行效率
但是它并不影响 child.before 的输出,并不是说我这里设定30字节,他就只能输出30字节了,这里的缓存区大小的意思应该类似于每满缓存区大小的时候,程式回去匹配一次看是否有满足条件

4,进阶切换shell环境交互
child.sendline() 是 pexpect.spawn 对象中的一个方法,用于向子进程发送一行命令,并自动在命令末尾添加一个换行符,我们可以利用此命令进行shell交互
child.sendline(‘cmd’),会在cmd后默认加上换行符,所以这个命令能被shell直接执行
先上代码:

import pexpect

child = pexpect.spawn('/bin/bash')
child.expect('#')  
child.sendline('ls -l')
child.expect('#')
print(child.before.decode('utf-8'))
child.sendline('date')
child.expect('#')
print(child.before.decode('utf-8'))

结果:

 ls -l
total 12
-rwxrwxrwx 1 root root 480 Jun 10 07:54 0.py
-rwxrwxrwx 1 root root 234 Jun 10 09:14 1.py
-rwxrwxrwx 1 root root  10 Jun 10 08:08 status.txt
root@raspberrypi:/home/pi/python3
 date
Sat 10 Jun 09:14:45 BST 2023
root@raspberrypi:/home/pi/python3

以上均为打印结果,因为我们启用了一个/bin/bash的子进程,它是一个shell环境,所以我们使用child.before输出时,它将shell cmd,以及这个shell cmd执行结果都打印了出来,又因为关键字为 #,所以他输出了#号前的所有输出,没有#
结束这个子进程可以使用child.kill() 或 child.close()
使用 child.kill() 方法可以强制终止子进程,并且会立即释放子进程占用的资源
使用 child.close() 方法会正常结束子进程,并且会等待子进程的缓冲区输出全部读取完成后才返回。这样一来,你可以确保程序正常退出,并且已经读取了所有子进程输出的数据。

5.再加ssh远程?
既然这么好用,我直接应用于远程环境应该不过分吧?
上代码:

import pexpect
import sys

try:
    child = pexpect.spawn('ssh root@192.168.9.102')
    while True:
        rec = child.expect(["yes/no","password:"])
        if rec == 0:
            child.sendline('yes')
        else:
            child.sendline('aa')
            result = child.expect(['#', 'Permission denied', pexpect.TIMEOUT])
            if result == 0:
                print("ssh success")
                break  
            elif result == 1:
                print("password error")
                sys.exit(1)  
            elif result == 2:
                print("ssh is timeout")
                sys.exit(1) 
    child.sendline('ls -la')
    child.expect('#')
    print(child.before.decode('utf-8'))

except pexpect.exceptions.EOF:
    print("ssh closed")
    sys.exit(1)

except pexpect.exceptions.TIMEOUT:
    print("cmd timeout")
    sys.exit(1)

except Exception as e:
    print("error:", e)
    sys.exit(1)

这里我们首先使用try-except语句来处理一些异常错误,如EOF,TIMEOUT等
这里就是使用while循环,首先检查ssh命令执行后打印为"yes/no"还是"password:“,如果是前者,则输入yes,然后while循环再来判断,如果是后者,就输入登录密码,我这里为"aa”
输入密码是有可能是错误密码的,所以这里我们多加了一个判断,判断是’#‘还是’Permission denied’,如果是"#“说明登录成功了(假如你登录的不是root用户,这个应该是”$",具体情况具体分析)
如果成功就跳出while循环,如果失败,或是直接验证密码超时,都直接停止
成功登录后,我们此时是一个shell环境,所以直接下我们需要执行的shell命令,这里我使用"ls -la"来实验,然后使用child.expect(‘#’)来等待执行结束
注意,如果你要执行的命令很久,假如是fio,需要加上timeout=xx,否则他默认30s没等到就直接超时退出了

然后下面 except就是一些一场状况的处理,共三种,EOF,TIMEOUT和其他

以上就是关于pexpect库的一些简单运用了

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值