• 自动交互式脚本--expect


       我们经常会遇到一些需要与服务器程序打交道的场景,比如,从登陆某个服务器,然后进行某项工作。这很平常,但是如果把这个工作自动化进行,你就需要一个程序能自动做你要告诉机器的事情,这样,我们的expect就能大显身手了。

       首先,expect是一个简单的工具语言,如要工作就是进行自动化的人机交互。它的作者对Expect的定义:是一个实现自动交互功能的软件套件(a software suite for automating interactive tools),使用expect,它能帮助我们在合适的情景下进行合适的交互。

          例子:我们要在凌晨登陆到一个linux服务器:192.168.1.1,然后执行一个命令做/home/test/a.sh,我们的思路是:写一个expect脚本,然后用crontab在凌晨运行。

        #!/usr/bin/expect -f
        set timeout 30
        spawn ssh -l test 192.168.1.1
        expect "password:"
        send "mypassword
    "
        expect "~$*"
        send "/home/test/a.sh
    "
        send "exit
    "
        expect eof
        exit
    

     expect 的核心功能,对于设定好的特定匹配形式,以相匹配的动作以应对。每一个expect后所跟的字符串(或者正则表达式)就是脚本所等待的匹配模式,每一个send 所做的工作就是对于各种的模式串,实施相应的动作。

        第一行设定了脚本执行的程序,-f选项指的是expect执行一个文件

        第二行,设定了本脚本所有的超时时间,单位是秒(s),如果超时,脚本将继续向下进行(比如在等待某个模式出现,超时以后,会进行下一语句)。

        第三行,expect使用spawn命令来启动脚本和命令会话,这里启动的是ssh命令,这里的ssh命令将会以子进程的方式产生。

        下面就是交互的过程:ssh -l 登陆以后,会给要求客户写入密码,所以等待出现“password:”,出现password:以后,需要写入密码,注意这里需要送去回车或者换行符,否则远端主机不会收到ssh请求的。登陆上系统之后,会出现命令提示符:~$,即系统已经登陆到了远端主机的shell,然后送去要执行的命令。完毕后推出远程机器(这个send "exit "前也可以有上一个命令的输出,也可以没有,因为上一个命令执行完毕后会顺序执行下一条)。

        最后是等待标示子进程已结束的标示符eof,然后退出。(注:这个等待eof必须要有,如果没有eof,很可能在子进程没有结束前就退出,造成问题。)

        下面的例子,介绍expect其他重要的命令,先看如下例子:

        #!/usr/bin/expect -f
        set timeout 10
        set myname [lindex $argv 0]
        spawn ./talk.sh
        expect "Name:"
        send "$myname
    "
        expect eof
    

     这个例子引入了输入参数的概念,就是在执行这个expect脚本时候,需要带入参数,比如这个脚本名字如果为test.ep

        执行时需要键入参数:./test.ep "John"

        set myname [lindex $argv 0] 这句获取外部传入的第一个参数(argv 0)并传给变量myname,如果获取多个参数则使用argv 1,argv 2,以此类推。

        另外,expect支持一般语言所常用的if,for等流程控制语句,这个可以参看expect高级介绍

    小结:

        expect是一款非常好用的自动化交互工具

    核心命令:

        spawn: 启动一个命令或程序,并由expect程序开始监听

        set :设置变量值和名称

        set .. lindex:从程序输入参数出获取变量值并赋给变量

        expect ...send对:expect等待希望出现的匹配串,对于匹配到的串,send发送命令进行执行。

    如何向expect脚本里面传递参数

    比如下面脚本用来做ssh无密码登陆,自动输入确认yes和密码信息,用户名,密码,hostname通过参数来传递
     
    ssh.exp
    Python代码  
    #!/usr/bin/expect  
    set timeout 10  
    set username [lindex $argv 0]  
    set password [lindex $argv 1]  
    set hostname [lindex $argv 2]  
    spawn ssh-copy-id -i .ssh/id_rsa.pub $username@$hostname  
    expect "yes/no"  
    send "yes
    "  
    expect "password:"  
    send "$password
    "   
    expect eof   
    执行脚本./ssh.exp root pasword hostname1
    
    expect接收参数的方式和bash脚本的方式不太一样,bash是通过$0 ... $n 这种方式,而expect是通过set <变量名称> [lindex $argv <param index>],例如set username [lindex $argv 0]
     

    expect用法

    1. [#!/usr/bin/expect] 

    这一行告诉操作系统脚本里的代码使用那一个shell来执行。这里的expect其实和linux下的bash、windows下的cmd是一类东西。 

    注意:这一行需要在脚本的第一行。 

    2. [set timeout 30] 

    基本上认识英文的都知道这是设置超时时间的,现在你只要记住他的计时单位是:秒   。timeout -1 为永不超时

    3. [spawn ssh -l username 192.168.1.1] 

    spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找 不到spawn命令的。所以不要用 “which spawn“之类的命令去找spawn命令。好比windows里的dir就是一个内部命令,这个命令由shell自带,你无法找到一个dir.com 或 dir.exe 的可执行文件。 

    它主要的功能是给ssh运行进程加个壳,用来传递交互指令。 

    4. [expect "password:"] 

    这里的expect也是expect的一个内部命令,有点晕吧,expect的shell命令和内部命令是一样的,但不是一个功能,习 惯就好了。这个命令的意思是判断上次输出结果里是否包含“password:”的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是 前面设置的30秒 

    5. [send "ispass "] 

    这里就是执行交互动作,与手工输入密码的动作等效。 

    温馨提示: 命令字符串结尾别忘记加上“ ”,如果出现异常等待的状态可以核查一下。 

    6. [interact] 

    执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。如果你只是登录过去执行 

    7.$argv 参数数组

    expect脚本可以接受从bash传递过来的参数.可以使用[lindex $argv n]获得,n从0开始,分别表示第一个,第二个,第三个....参数

    下面的expect脚本的例子

    执行这个文件./launch.exp 1 2 3

    屏幕上就会分别打印出参数

    send_user用来发送内容给用户。

    参数运用方面还有很多技巧

    比如$argc 存储了参数个数,args被结构化成一个列表存在argv。$argv0 被初始化为脚本名字。

    除此之外,如果你在第一行(#!那行)使用-d (debug参数),可以在运行的时候输出一些很有用的信息

    比如你会看见

    argv[0] = /usr/bin/expect argv[1] = -d argv[2] = ./launch.exp argv[3] = 1 argv[4] = 2 argv[5] = 3

    使用这些也可以完成参数传递

    8.

    expect的命令行参数参考了c语言的,与bash shell有点不一样。其中,$argc为命令行参数的个数,$argv0为脚本名字本身,$argv为命令行参数。[lrange $argv 0 0]表示第1个参数,[lrange $argv 0 4]为第一个到第五个参数。与c语言不一样的地方在于,$argv不包含脚本名字本身。

    9. exp_continue的用法

    #!/usr/bin/expect -f
    
    set ipaddr "localhost"
    
    set passwd "iforgot"
    
    spawn ssh root@$ipaddr              #spawn   意思是执行命令,expect内命令,shell中不存在
    
    expect {
    
    "yes/no" { send "yes
    "; exp_continue}
    
    "password:" { send "$passwd
    " }
    
    }
    
    expect "]# "
    
    send "touch a.txt
    "                       #意思为发送命令
    
    send "exit
    "
    
    expect eof
    
    exit
    

    exp_continue可以继续执行下面的匹配,简单了许多。还有一点,让我认识到匹配不见得要匹配最后几个字符。

    10.拿来小例子   

    设置变量     set PASSWD   abcd123

    #!/usr/bin/expect -f
    
    # Expect script to supply root/admin password for remote ssh server
    
    # and execute command.
    
    # This script needs three argument to(s) connect to remote server:
    
    # password = Password of remote UNIX server, for root user.
    
    # ipaddr = IP Addreess of remote UNIX server, no hostname
    
    # scriptname = Path to remote script which will execute on remote server
    
    # If you username and passwd has not pass the rsa trust, your login will fail.
    
    # Usage For example:
    
    #  ./sshlogin.exp password 192.168.1.11 who
    
    # ------------------------------------------------------------------------
    
    # Copyright (c) 2004 nixCraft project <http://cyberciti.biz/fb/>
    
    # This script is licensed under GNU GPL version 2.0 or above
    
    # -------------------------------------------------------------------------
    
    # This script is part of nixCraft shell script collection (NSSC)
    
    # Visit http://bash.cyberciti.biz/ for more information.
    
    # ----------------------------------------------------------------------
    
    # set Variables
    
    set password [lrange $argv 0 0]
    
    set ipaddr [lrange $argv 1 1]
    
    set scriptname [lrange $argv 2 2]
    
    set arg1 [lrange $argv 3 3]
    
    set timeout -1
    
    # now connect to remote UNIX box (ipaddr) with given script to execute
    
    spawn ssh yourusername@$ipaddr $scriptname $arg1
    
    match_max 100000
    
    # Look for passwod prompt
    
    expect "*?assword:*"
    
    # Send password aka $password
    
    send -- "$password
    "
    
    # send blank line (
    ) to make sure we get back to gui
    
    send -- "
    "
    
    expect eof
    
     
    #!/usr/bin/expect 
    
     # 设置超时时间为 60 秒
    
     set timeout  60                                         
    
     # 设置要登录的主机 IP 地址
    
     set host 192.168.1.46
    
     # 设置以什么名字的用户登录
    
     set name root 
    
     # 设置用户名的登录密码
    
     set password 123456 
    
     
    
     #spawn 一个 ssh 登录进程
    
     spawn  ssh $host -l $name 
    
     # 等待响应,第一次登录往往会提示是否永久保存 RSA 到本机的 know hosts 列表中;等到回答后,在提示输出密码;之后就直接提示输入密码
    
     expect { 
    
        "(yes/no)?" { 
    
            send "yes
    "
    
            expect "assword:"
    
            send "$pasword
    "
    
        } 
    
            "assword:" { 
    
            send "$password
    "
    
        } 
    
     } 
    
     expect "#"
    
     # 下面测试是否登录到 $host 
    
     send "uname
    "
    
     expect "Linux"
    
     send_user  "Now you can do some operation on this terminal
    "
    
     # 这里使用了 interact 命令,使执行完程序后,用户可以在 $host 终端进行交互操作。
    
     Interact 
    

    用expect实现ssh自动登录对服务器进行批量管理

    1.实现ssh自动登录完成任务的expect脚本

    #!/usr/bin/expect -f
    
    set ipaddress [lindex $argv 0]
    
    set passwd [lindex $argv 1]
    
    set timeout 30
    
    spawn ssh shellqun@$ipaddress
    
    expect {
    
    "yes/no" { send "yes
    ";exp_continue }
    
    "password:" { send "$passwd
    " }
    
    }
    
    expect "*from*"
    
    send "mkdir -p ./tmp/testfile
    "
    
    #send "exit
    "
    
    expect "#"  命令运行完, 你要期待一个结果, 结果就是返回shell提示符了(是# 或者$)
    
    #最后一句第13行的解释:
    
     
    
    其实写成 interact 的最大好处是登录后不会退出,而会一直保持会话连接,可以后续手动处理其它任务,请根据实际情况自行选择了。
    

     2.调用login.exp完成批量管理

    #!/bin/bash
    
    for i in `awk '{print $1}' passwd.txt`
    
    do
    
    j=`awk -v I="$i" '{if(I==$1)print $2}' passwd.txt`
    
    expect /root/shell/login.exp $i $j
    
    done
    

    linux下的expect的简单用法及举例

     1、使用expect前,需要先安装两个rpm包,下载:http://download.csdn.net/detail/wang7dao/4416172

    # rpm -ihv expect-5.43.0-8.el5.i386.rpm
    # rpm -ihv expect-devel-5.43.0-8.el5.i386.rpm
    

     2、使用脚本文件的例子--实现自动输密码

    #!/usr/bin/expect -f
    set password 123456
    #download
    spawn scp root@192.168.1.218:/root/a.wmv /home/yangyz/
    set timeout 300 
    expect "root@192.168.1.218's password:"
    set timeout 300 
    send "$password
    "
    set timeout 300 
    send "exit
    "
    expect eof   www.2cto.com  
    

     3、在sh脚本中嵌入expect的例子--通过连上一个公网的服务器再转跳到一个内网的服务器上,用脚本实现不用输密码,直接使用./goto.sh servername

    #!/bin/bash
    passmsmallq10="a"
    passzhsh="a"
    passfcwr="b"
    passwapfx="c"
    passadfx="d"
     
    ip1="200.100.10.10"
    ip2="10.100.100.70"
    ip3="10.100.100.60"
    ip4="10.100.100.10"
    ip5="10.100.100.20"
     
    case $1 in 
    "zhsh") passstr=$passzhsh ipstr=$ip2 ;;
    "fcwr") passstr=$passfcwr ipstr=$ip3 ;;
    "wapfx") passstr=$passwapfx ipstr=$ip4 ;;
    "adfx") passstr=$passadfx ipstr=$ip5 ;;
    *) echo "The parameter $1 isn't exist"
    exit 0 ;;  www.2cto.com  
    esac
     
    
    command1="ssh -l m_smallq -p 36000 $ip1"
    command2="ssh -l mqq -p 36000 $ipstr"
     
    expect -c "
            set timeout 60;
            spawn $command1;
            expect {
                    "221.130.15.10's password:" {send "$passmsmallq10
    "; exp_continue}
                    "m_smallq" {send "$command2
    "; exp_continue}
                    "mqq's password:" {send "$passstr
    ";interact}
                    }
            "
    
    对上面例子的expect的解说
    expect -c "..."  --里面输入命令
    expect {...}     --里面的多行记录,从上向下扫描匹配,谁先匹配谁先处理。
      www.2cto.com 

    4、ssh到另一台机子执行df -h后退出,要点是send后面可以跟多个命令,通过 来分行成多个命令

    #!/bin/bash
    ip1="183.62.178.191"
    command1="ssh -l root -p 14322 $ip1"
     
    expect -c "
            spawn $command1;
            expect {
                    "183.62.178.191's password:" {send "aa
    "; exp_continue}
                    "root@" {send "df -h
     exit
    "; exp_continue}
                    }
            "
    

     

     

  • 相关阅读:
    CSS盒子模型
    getContextPath、getServletPath、getRequestURI、request.getRealPath的区别
    MYSQL中的CASE WHEN END AS
    单点登录的精华总结
    git&github
    June 21st 2017 Week 25th Wednesday
    June 20th 2017 Week 25th Tuesday
    June 19th 2017 Week 25th Monday
    June 18th 2017 Week 25th Sunday
    June 17th 2017 Week 24th Saturday
  • 原文地址:https://www.cnblogs.com/zhuiluoyu/p/4873869.html
Copyright © 2020-2023  润新知