zoukankan      html  css  js  c++  java
  • 8.python 系统批量运维管理器之pexpect模块

    小插曲

    前几节讲了paramiko模块,但是pexpect模块的功能几乎跟paramiko一样,先来分析一下:

    1.各自介绍

    pexpect是一个通过启动子程序,使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的python模块。

    paramiko是一个基于python实现的ssh远程安全连接,用于ssh远程执行命令,文件传输等功能的ssh客户端模块。

    2.功能区别

    pexpect需要借助linux下的ssh命令方式登陆,实现类似scp的拷贝文件功能。

    paramiko无法实现类似pexpect的interact方法进行交互式命令输入,并且自身不支持多线程。

    3.使用场景

    使用python来作自动化登陆,并执行命令

    pexpect模块的使用偏向于偏交互式的使用,如:管理员需要登陆100台机器,每次都会手动执行不同的命令,如果通过ssh的命令进行登陆,这样每次输入不同的密码,用户,主机地址等信息会是一个不小的工作量,用pexpect这个模块,就可以解决问题。

    paramiko模块实现ssh的登陆探测,因为其更加通用并且兼容各种ssh协议的操作系统和相关的环境,并且可以实现类似sftp登陆验证。

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    pexpect可以理解成Linux下的expect的python封装,通过expect我们可以实现ssh,ftp,telnet等命令行进行自动交互,包括输入主机地址,用户名,密码,上传文件等,待出现异常我们还可以进行尝试自动处理。

    pexpect安装:pip install pexcept 即可

    pexpect的核心组件:

    1.spawn类

    spawn在windows无法运行,在linux上可以运行

    spawn是pexpect的主要类接口,功能是启动和控制子应用程序,以下是它的构造函数:

    class pexpect.spawn(command,args=[],timeout=30,maxread=2000,searchwindowsize=None,logfile=None,cwd=None,env=None,ignore_sighup=True)

    参数说明:

    • command:可以是任意已知的系统命令。
    child = pexpect.spawn('/usr/bin/ftp')    #启动ftp客户端命令
    child = pexpect.spawn('/usr/bin/ssh user@example.com')   #启动ssh远程连接命令
    child = pexpect.spawn('ls -latr /tmp')   #运行ls显示/tmp目录内容命令

    当子程序需要参数时:

    child = pexpect.spawn('/usr/bin/ftp',[])  
    child = pexpect.spawn('/usr/bin/ssh',['user@example.com']) 
    child = pexpect.spawn('ls',['-latr','/tmp'])
    • timeout:等待结果的超时时间。
    • maxread:为pexpect从终端控制台一次读取的最大字节数。
    • searchwindowsize:匹配缓冲区字符串的位置,默认是从开始位置匹配。

    需要注意的是,pexpect不会解析shell命令当中的元字符,包括重定向 ">",管道 "|",通配符 "*",当然可以通过将存在这三个特殊元字符命令作为/bin/bash的参数进行调用,像这样:

    child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > logs.txt"')
    child.expect(pexpect.EOF)

    也可以通过将命令的参数以python列表的形式进行替换:

    shell_cmd = 'ls -l | grep LOG > logs.txt'
    child = pexpect.spawn('/bin/bash',['-c',shell_cmd]
    ) child.expect(pexpect.EOF)

    有时候调试代码,需要获取pexpect的输入与输出信息,以便了解匹配情况。pexpect提供了两种途径,一种为写到日志文件,另一种为输出到标准输出。

    写到日志文件的实现方法如下:

    child = pexpect.spawn(command)
    file = open('mylog.txt','w')
    child.logfile = file

    获取标准输出的方法如下:

    child = pexpect.spawn(command)
    child.logfile_read = sys.stdout

    获取发送的内容:

    child.logfile_send = sys.stdout

    上面的语句仅仅在屏幕上打印向程序发送的内容。

    下面代码实现ssh登陆,登陆成功后显示/home目录文件清单,并通过日志文件记录所有的输入与输出:

    import pexpect
    import sys
    
    child = pexpect.spawn('ssh root@192.168.0.132')
    file = open('mylog.txt','w')
    child.logfile = file
    #child.logfile = sys.stdout
    
    child.expect(
    "password: ") child.sendline("12580") child.expect('#') child.sendline('ls /home') child.expect('#')

    下面是mylog.txt日志的内容,不过默认是二进制的方式存储:

    上面代码反复使用expect,read方法,这里来介绍一下:

    (1)expect方法

    expect定义了一个子程序输出的匹配规则。

    expect(pattern_list,timeout=-1,searchwindowsize=-1)

    参数解释:

    • pattern_list:正则表达式列表,表示要匹配的内容
    • timeout:不设置或者设置为-1时,超时时间就采用self.timeout的值,默认是30秒,也可以自己设置
    • searchwindowsize:功能上和spawn一样,但是还有很大区别,下面会具体说明
    在这里的 searchwindowsize 是在 expect() 方法中真正生效的,默认情况下是 None,也就是每从子进程中获取一个字符就做一次完整匹配,如果子进程的输出很多的话……性能会非常低。如果设置为其他的值,表示从子进程中读取到多少个字符才做一次匹配,这样会显著减少匹配的次数,增加性能。
     
    1.最简单的匹配方式
    process.expect('[Nn]ame')

    上面的代码表示:匹配 process 这个句柄(代表 spawn 方法的例子中我们启动的 ftp 连接)中的 name 关键字,其中 n 不分大小写。

    上面的关键字一旦匹配,就会返回0表示匹配成功,但是如果一直匹配不到呢?默认是会一直等下去,但是如果设置了 timeout 的话就会超时。

    2.匹配一系列输出

    实际上, expect() 可以匹配一系列输出,通过检查匹配到的输出,我们可以做不同的事情。比如之前 spawn 的 ftp 连接,如果我们输入用户名之后有不同的情况,就可以通过监控这些不同情况来做不同的动作,比如:

    index = process.expect([
        'Permission Denied',
        'Terminal type',
        'ftp>',
    ])
    if index == 0:
        print "Permission denied at host, can't login."
        process.kill(0)
    elif index == 1:
        print "Login ok, set up terminal type…"
        process.sendline('vty100')
        process.expect("ftp>")
    elif index == 2:
        print "Login Ok, please send your command"
        process.interact()

    上面的代码中,expect 方法中的是一个列表,列表中的每个元素都是一个关键字的正则表达式,也就是说我们期待这 3 种情况之一,而 expect 返回一个顺序值来代表我匹配到了哪一个元素(也就是发生了哪种情况了),这个顺序值是从 0 开始计算的。

    当expect之后,下面的 if 语句就开始处理这 3 种情况了:

    1. 权限不足,这可能是 ftp 服务器出现问题,或者没有这个帐号,发现这种情况的话,我们就给用户提示一下,然后杀掉进程
    2. 登陆成功,但还要用户指定终端模式才能真正使用,所以我们在代码中指定了 vty100 这种模式,然后看是不是能真正使用了
    3. 还是登陆成功了,而且还可以直接输入命令操作 ftp 服务器了,于是我们提示用户,然后把操作权限交给用户

    另外有一种特殊情况,如果同时有2个被匹配到,那么怎么办?简单来说就是这样:

    1. 原始流中,第一个被关键字匹配到的内容会被使用
    2. 匹配关键字列表中,最左边的会被使用

    给个例子:

    import pexpect
    child = pexpect.spawn("echo 'foobar'")
    print(child.expect(['bar','foo','foobar']))
    
    输出:1,即 'foo' 被匹配

    使用技巧

    1. 如果要检查或者匹配 expect.EOF 和 expect.TIMEOUT 这两种情形,那么必须将它们放进匹配列表里面去,这样可以通过检查返回的数字来处理它们。如果没放进列表的话,就会发生 EOF 或者 TIMEOUT 错误,程序就会中途停止了

    2. 匹配规则中有些特殊语法,比如下面的规则中前 2 个匹配都是大小写无关的,关键就是这个 (?i) 匹配规则,它相当于 re.IGNORE 或者 re.I 这个关键字,因为毕竟不是真正的正则表达式引擎,所以 pexpect 使用这样特殊语法:

      child.expect(['(?i)etc', '(?i)readme', pexpect.EOF, pexpect.TIMEOUT])

    (2)send方法

    下面这些输出的方法的作用都是向子程序发送响应命令,可以理解成代替了我们的标准输入:

    1.send()         用来向程序发送指定的字符串

    2.sendline()    用来发送带回车符的字符串

    sendline() 和 send() 唯一的区别就是在发送的字符串后面加上了回车换行符,这也使它们用在了不同的地方:

    • 只需要发送字符就可以的话用send()
    • 如果发送字符后还要回车的话,就用 sendline()

    它也会返回发送的字符数量

    3.sendcontrol()   发送控制信号

    sendcontrol()向子程序发送控制字符,比如 "ctrl+c","ctrl+d"...可以这样写

    process.sendcontrol('c')

    4.sendeof()   发送EOF信号

    5.interact()    将控制权交给用户

    interact() 表示将控制权限交给用户(或者说标准输入)。一般情况下 pexpect 会接管所有的输入和输出,但有的时候还是希望用户介入,或者仅仅是为了完成一部分工作的时候, interact() 就很有用了。

    比如:

    1. 登陆 ftp 服务器的时候,在输入用户密码阶段希望用户手工输入密码,然后脚本完成剩余工作时(将用户密码写在脚本中可不安全)
    2. 只希望完成登陆工作,比如要 ssh 连接到一台远方的服务器,但中间要经过好几跳,用手工输入实在太麻烦,所以就用脚本先跳到目的服务器上,然后再把控制权限还给用户做操作。

    使用方法:

    # escape_character 就是当用户输出这里指定的字符以后表示自己的操作完成了,将控制权重新交给 pexpect
    process.interact(escape_character
    ='x1d', input_filter=None, output_filter= None)

    详细来说,这个方法将控制权交给用户(或者说用户操作的键盘),然后简单的将标准输出、标准错误输出和标准输入绑定到系统上来。

    通过设置 escape_character 的值,可以定义返回码,默认是 <kbd>ctrl+]</kbd> 或者说 <kbd>^]</kbd>,当输入了返回码以后,脚本会将控制权从用户那里重新拿回来,然后继续向下执行。

    6.close()

    如果想中途关闭子程序,那么可以用 close 来完成,调用这个方法后会返回这个程序的返回值。

    如果设置 force=True 会强行关闭这个程序,大概的过程就是先发送 SIGHUP 和 SIGINT 信号,如果都无效的话就发 SIGKILL 信号,反正不管怎么样都会保证这个程序被关闭掉。

    多次调用这个方法是允许的,但是不保证每次都能返回正确的返回值。尽量不要这么做,如果想保证程序被关闭的话只要设置force的值就可以了。

    下面是实例:

    process.close(force=True)

    7.cwd  指定命令执行的目录

    默认值: None 或者说 ./

    cwd 用来指定命令发送的命令在哪个路径下执行,它一般是用在 send() 系列命令中,比如在 Linux 中,你想在 /etc 目录下执行 ls –l 命令,那么完全不需要用sendline("cd /etc &&ls -l") 这样的方式,而是用 sendline("ls -l",cwd="/etc") 就可以了。

    8.env   指定环境变量

    默认值: None

    指定环境变量的值,这个值是一个字典,如果你发送的命令要使用一些环境变量,那么可以在这里提供

    (3)特殊变量

    1.pexpect.EOF   匹配终止信号

    EOF 变量使用范围很广泛,比如检查 ssh/ftp/telnet 连接是否终止啊,文件是否已经到达末尾啊。 pexpect 大部分脚本的最后都会检查 EOF 变量来判断是不是正常终止和退出,比如下面的代码:
    process.expect("ftp>")
    process.sendline("by")
    process.expect(pexpect.EOF)
    print("ftp connect terminated.")

    2.pexpect.TIMEOUT  匹配超时信号

    TIMEOUT 变量用来匹配超时的情况,默认情况下 expect 的超时时间是 60 秒,如果超过 60 秒还没有发现期待的关键字,就会触发这个行为,比如:
    # 匹配pexpect.TIMEOUT的动作,只有超时事件发生的时候才会有效
    index = process.expect(['ftp>', pexpect.TIMEOUT],)
    if index == 1:
        process.interactive()   ; # 将控制权交给用户
    elif index == 2:
        print "Time is out."
        process.kill(0)         ; # 杀掉进程
    
    
    
    # 那么怎么改变超时时间呢?其实可以修改spawn对象里的timeout参数:
    # 下面的例子仅仅加了一行,这样就改变了超时的时间了
    process.timeout = 300   ; # 注意这一行
    index = process.expect(['ftp>', pexpect.TIMEOUT],)
    if index == 1:
        process.interactive()   ; # 将控制权交给用户
    elif index == 2:
        print "Time is out."
        process.kill(0)         ; # 杀掉进程

    3.process.before/after/match 获取程序运行输出

    当 expect() 过程匹配到关键字(或者说正则表达式)之后,系统会自动给3个变量赋值,分别是 before, after 和 match

    • process.before - 保存了到匹配到关键字为止,缓存里面已有的所有数据。也就是说如果缓存里缓存了 100 个字符的时候终于匹配到了关键字,那么 before 就是除了匹配到的关键字之外的所有字符
    • process.after - 保存匹配到的关键字,比如你在 expect 里面使用了正则表达式,那么表达式匹配到的所有字符都在 after 里面
    • process.match - 保存的是匹配到的正则表达式的实例,和上面的 after 相比一个是匹配到的字符串,一个是匹配到的正则表达式实例

    如果 expect() 过程中发生错误,那么 before 保存到目前位置缓存里的所有数据, after 和 match 都是 None

    (4) run函数
    run函数是使用pexpect进行封装的调用外部命令的函数,类似于os.system或os.popen方法,不同的是,使用run()可以同时获得命令的输出结果以及命令的退出状态。
    pexpect.run(command,timeout=-1,withexitstatus=False,events=None,extra_args=None,logfile=None,cwd=None,env=None)

    参数说明:

    • command:系统已知的任意命令,如果没有写绝对路径时将会尝试搜索命令的路径。
    • events:是一个字典,定义了expect及sendline方法的对应关系。

    spawn方式的例子如下:

    from pexpect import *
    child = spawn('scp foo root@192.168.0.132:.')
    child.expect('(?!)password')
    child.sendline(mypassword)

    使用run函数的话:

    from pexpect import *
    run('scp foo root@192.168.0.132:.',events={'(?!)password':mypassword})

    (5)pxssh类

    pxssh是pexpect的派生类,针对在ssh会话操作上再做一层封装,提供与基类更加直接的操作方法。

    class pexpect.pxssh.pxssh(timeout=30,maxread=2000,searchwindowsize=None,logfile=None,cwd=None,env=None)

    pxssh常用的三个方法如下:

    • login():建立ssh连接。
    • logout():断开连接。
    • prompt():等待系统提示符,用于等待命令执行结束。

    下面使用pxssh类实现一个ssh连接远程主机并执行命令的示例。首先使用login()方法与远程主机建立连接,再通过sendline()方法发送执行的命令,prompt()方法等待命令执行结束且出现系统提示符,最后使用logout()方法端口连接。

    from pexpect import pxssh
    import getpass
    try:
        #调用构造函数,创建一个pxssh类的对象
    s = pxssh.pxssh()

        hostname = input('hostname: ')
        username = input('username: ')
        password = getpass.getpass('password: ')

    #利用pxssh类的login方法进行ssh登陆,原始prompt为'$','#'或'>'

        s.login(hostname, username, password,original_prompt='[$#>]')
        s.sendline('uptime')   #运行uptime命令
        s.prompt()             #匹配系统提示符
        print(s.before)        #打印出现系统提示符前的命令输出
        s.sendline('ls -l')
        s.prompt()
        print(s.before)
        s.sendline('df')
        s.prompt()
        print(s.before)
        s.logout() #断开ssh连接
    except pxssh.ExceptionPxssh as e:
        print("pxssh failed on login.")
        print(e)

    Pexpect应用示例

    1.实现一个自动化FTP操作

    使用pexpect模块的spawn()方法执行FTP命令,通过expect()方法定义匹配的输出规则,sendline()方法执行相关FTP交互命令。

    from __future__ import unicode_literals   #使用unicode编码
     
    import pexpect
    import sys
     
    #运行ftp命令
    child = pexpect.spawn('ftp 192.168.0.132')

    #(?i)标识后面的字符串正则匹配忽略大小写
    child.expect('(?i)name .*: ')

    #输入ftp账号信息
    child.sendline('账号')

    #匹配密码输入提示
    child.expect('(?i)password')

    #输入ftp密码
    child.sendline('密码')
    child.expect('ftp> ')

    #启用二进制传输模式
    child.sendline('bin')
    child.expect('ftp> ')

    #下载robots.txt

    child.sendline('get robot.txt')
    child.expect('ftp> ')

    #输出匹配的ftp > 之前的输入与输出

    sys.stdout.write(child.before.decode('utf-8'))
    print("Escape character is '^]'. ")
    sys.stdout.write(child.after.decode('utf-8'))
    sys.stdout.flush()

    #调用interact让出控制权,用户可以继续当前的会话手工控制子程序,默认输入“^]”字符跳出
    child.interact()
    child.sendline('bye')
    child.close()

    运行结果如下:

    最后 ftp>  是调用interact()控制项让出,用户可以手工交互

    2.远程文件自动打包下载
    import pexpect
    import sys
    
    ip="192.168.0.132"   #定义目标主机
    user="root"       #目标主机用户
    passwd="123456"
    target_file="/data/logs/nginx.log"   #目标主机nginx日志文件
    
    child=pexpect.spawn('/usr/bin/ssh', [user+'@'+ip])  #运行ssh命令
    fout=open('mylog.txt','wb')  #输入,输出日志写入mylog.txt文件
    child.logfile=fout
    
    try:
        child.expect('(?i)password')   #匹配password字符串,(?!)表示不区分大小写
        child.sendline(passwd)
        child.expect('#')
        child.sendline('tar -zcf /data/logs/nginx.tar.gz ' +target_file) #打包nginx日志文件
        child.expect('#')
        print(child.before)
        child.sendline('exit')
        fout.close()
    except EOF:     #定义EOF异常处理
        print("expect EOF")
    except TIMEOUT:   #定义TIMEOUT异常处理
        print("expect TIMEOUT")
    
    child=pexpect.spawn('/usr/bin/scp', [user+'@'+ip+':/data/logs/nginx.tar.gz','/home'])   #启动scp远程拷贝命令,实现将打包好的nginx日志复制到/home目录下
    fout=file('mylog.txt','a')
    child.logfile=fout
    
    try:
        child.expect('(?i)password')
        child.sendline(passwd)
        child.expect(pexpect.EOF)   #匹配缓冲区EOF(结尾),保证文件复制正常完成
    except EOF: print(
    "expect EOF") except TIMEOUT: print("expect TIMEOUT")

     3.完整实现ftp登陆,下载文件到本地

    # coding=UTF-8
    import pexpect
    
    # 即将 ftp 所要登录的远程主机的域名
    ipAddress = '192.168.0.132'
    
    # 登录用户名
    loginName = 'root'
    
    # 用户名密码
    loginPassword = '12580'
    
    # 拼凑 ftp 命令
    cmd = 'ftp ' + ipAddress
    
    # 利用 ftp 命令作为 spawn 类构造函数的参数,生成一个 spawn 类的对象
    child = pexpect.spawn(cmd)
    
    # 期望具有提示输入用户名的字符出现
    index = child.expect(["(?i)name", "(?i)Unknown host", pexpect.EOF, pexpect.TIMEOUT])
    
    # 匹配到了 "(?i)name",表明接下来要输入用户名
    if index == 0:
        # 发送登录用户名 + 换行符给子程序.
        child.sendline(loginName)
    # 期望
    "(?i)password" 具有提示输入密码的字符出现. index = child.expect(["(?i)password", pexpect.EOF, pexpect.TIMEOUT]) # 匹配到了 pexpect.EOF 或 pexpect.TIMEOUT,表示超时或者 EOF,程序打印提示信息并退出. if (index != 0): print("ftp login failed") child.close(force=True) # 匹配到了密码提示符,发送密码 + 换行符给子程序. child.sendline(loginPassword) # 期望登录成功后,提示符 "ftp>" 字符出现. index = child.expect( ['ftp>', 'Login incorrect', 'Service not available', pexpect.EOF, pexpect.TIMEOUT]) # 匹配到了 'ftp>',登录成功. if (index == 0): print('Congratulations! ftp login correct!') # 发送 'bin'+ 换行符给子程序,表示接下来使用二进制模式来传输文件. child.sendline("bin") print('getting a file...') # 向子程序发送下载文件 rmall 的命令. child.sendline("get ftptest.txt") # 期望下载成功后,出现 'Transfer complete.*ftp>',其实下载成功后, # 会出现以下类似于以下的提示信息: # 200 PORT command successful. # 150 Opening data connection for rmall (548 bytes). # 226 Transfer complete. # 548 bytes received in 0.00019 seconds (2.8e+03 Kbytes/s) # 所以直接用正则表达式 '.*''Transfer complete' 和提示符 'ftp>' 之间的字符全省去. index = child.expect( ['Transfer complete.*ftp>', pexpect.EOF, pexpect.TIMEOUT] ) # 匹配到了 pexpect.EOF 或 pexpect.TIMEOUT,表示超时或者 EOF,程序打印提示信息并退出. if (index != 0): print("failed to get the file") child.close(force=True) # 匹配到了 'Transfer complete.*ftp>',表明下载文件成功,打印成功信息,并输入 'bye',结束 ftp session. print('successfully received the file') child.sendline("bye") # 用户名或密码不对,会先出现 'Login incorrect',然后仍会出现 'ftp>',但是 pexpect 是最小匹配,不是贪婪匹配, # 所以如果用户名或密码不对,会匹配到 'Login incorrect',而不是 'ftp>',然后程序打印提示信息并退出. elif (index == 1): print("You entered an invalid login name or password. Program quits!") child.close(force=True) # 匹配到了 'Service not available',一般表明 421 Service not available, remote server has # closed connection,程序打印提示信息并退出. # 匹配到了 pexpect.EOF 或 pexpect.TIMEOUT,表示超时或者 EOF,程序打印提示信息并退出. else: print("ftp login failed! index = " + index) child.close(force=True) # 匹配到了 "(?i)Unknown host",表示 server 地址不对,程序打印提示信息并退出 elif index == 1 : print("ftp login failed, due to unknown host") child.close(force=True) # 匹配到了 pexpect.EOF 或 pexpect.TIMEOUT,表示超时或者 EOF,程序打印提示信息并退出 else: print("ftp login failed, due to TIMEOUT or EOF") child.close(force=True)

    输出结果:

    4.ssh登陆并执行命令,获取命令返回结果

    #coding=utf-8
    """
    This runs a command on a remote host using SSH. At the prompts enter hostname,
    user, password and the command.
    """
    
    import pexpect
    import getpass
    import os
    import traceback
    
    #user: ssh 主机的用户名
    #host:ssh 主机的域名
    #password:ssh 主机的密码
    #command:即将在远端 ssh 主机上运行的命令
    def ssh_command (user, host, password, command):
        """
        This runs a command on the remote host. This could also be done with the
        pxssh class, but this demonstrates what that class does at a simpler level.
        This returns a pexpect.spawn object. This handles the case when you try to
        connect to a new host and ssh asks you if you want to accept the public key
        fingerprint and continue connecting.
        """
        ssh_newkey = 'Are you sure you want to continue connecting'
        # 为 ssh 命令生成一个 spawn 类的子程序对象.
        child = pexpect.spawn('ssh -l %s %s %s'%(user, host, command))
        i = child.expect([pexpect.TIMEOUT, ssh_newkey, 'password: '])
        # 如果登录超时,打印出错信息,并退出.
        if i == 0: # Timeout
            print('ERROR!')
            print('SSH could not login. Here is what SSH said:')
            print(child.before, child.after)
            return None
        # 如果 ssh 没有 public key,接受它.
        if i == 1: # SSH does not have the public key. Just accept it.
            child.sendline('yes')
            child.expect('password: ')
            i = child.expect([pexpect.TIMEOUT, 'password: '])
            if i == 0: 
            # Timeout
                print('ERROR!')
                print('SSH could not login. Here is what SSH said:')
                print(child.before, child.after)
                return None
            # 输入密码.
            child.sendline(password)
            return child
        if i == 2:
            # 输入密码.
            child.sendline(password)
            return child
    
    def main ():
        # 获得用户指定 ssh 主机域名.
        host = input('Hostname: ')
      
        # 获得用户指定 ssh 主机用户名.
        user = input('User: ')
        
        # 获得用户指定 ssh 主机密码.
        password = getpass.getpass()
    
        # 获得用户指定 ssh 主机上即将运行的命令.
        command = input('Enter the command: ')
        child = ssh_command(user, host, password, command)
        # 匹配 pexpect.EOF
        child.expect(pexpect.EOF,timeout=180)
        # 输出命令结果.
        print(child.before.strip().decode('utf-8'))
    
    if __name__ == '__main__':
        try:
            main()
        except Exception:
            print("ERROR!")
            traceback.print_exc()
            os._exit(1)

    执行结果:

    参考链接:https://www.oschina.net/question/12_7583

  • 相关阅读:
    线程和信号
    线程取消状态和取消类型
    线程本地缓存
    线程安全函数的概念
    线程/同步对象的属性对象
    查看安全策略
    ss性能
    三次握手四次断开
    线程同步--屏障
    vs2008 编译时候 自动关闭 问题解决方法
  • 原文地址:https://www.cnblogs.com/bmjoker/p/10583809.html
Copyright © 2011-2022 走看看