关于 linux expect 用法、示例

=======================================
关于expect
date:2023-05-18
=======================================
参考文档:
linux expect 详解_linux_初码诛仙-DevPress官方社区.mhtml

=======================================
解释:expect 用于linux环境下,自动交互,如shell执行,需要手动需输入密码场景
        expect 需要安装

  • 1、命令速查

    spawn:交互程序开始后面跟命令或者指定程序(在壳内启动这个进程)
    expect:获取匹配信息匹配成功则执行expect后面的程序动作(检测由壳内进程发出的特定交互指令反馈字符串后向下执行)
    expect eof:退出expect
    expect_out:获取expect输出字符
    send:用于向进程发送字符串(从壳外向壳内进程发送一条字符串,换行符为确认结束)
    interact:允许用户交互
    exp_continue:在expect中多次匹配就需要用到
    send_user:用来打印输出 相当于shell中的echo
    send_error:用来打印输出 相当于shell中的echo ( 貌似和send_user 没区别一样 )
    exit:退出expect脚本
    eof:expect执行结束 退出
    set:定义变量
    puts:输出变量
    set timeout:设置超时时间

  • 2、常用命令解析

    如下将expect 嵌套于shell 中。
    2.1、解释器
        使用expect时,需要expect解释器,expect代码包含在
            /usr/bin/expect <<-EOF        #注意这个 “ - ”
                expect代码
            EOF
    2.2、spawn & expect
        spawn:
            启动一个命令
            spawn "cmd"
        expect:
            监控spawn命令执行结果输出,去匹配关键字,然后动作。
            expect {    #这里中括号必须与expect同一行
                        "关键字1" {动作1}
                        "关键字2" {动作2}
                        "关键字N" {send "yes\r";exp_continue}
                    }
            Tips:如果expect对所有的关键字匹配不上会出现超时报错
                    #expect: spawn id exp4 not open
                    #while executing
                    #"expect eof"
        2.2.1 expect输出值获取
            expect " " {
                            set raw $expect_out(buffer)
                            # remove final carriage return
                            set response [string trimright "$raw" " "]
                        }
        2.2.2    expect 判断语句
            if {"$response" == ""} {set response $def}
        
    2.3、send
        命令发送,配合expect匹配关键字后使用
        *注意send 输出,也可以被expect监控,可用于send执行结果判断
        
        
    2.4、send_user、send_error
        相当于shell 的echo
            换行符 \r \n
            \r: 回到本行开头 (在send 命令表示回车)
            \n: 换行、回车
                使用\n 换行, \r换行会导致当前行不显示
                EXP:
                    ******
                    expect {
                                "*Permission denied, please try again*" {send_user "\n***********root密码错误,退出当前连接!\n";exit 1}
                            }
    2.5、exp_continue
        类似for、while中的continue
    
    2.6、参数传递
        用于expect是独立脚本情况
        expect嵌套在shell 中时,可直接条用shell中变量
            argv[n]:    参数
            argc:        表示参数的数量
                #!/usr/bin/expect
                set uname [lindex $argv 0]
                set pwd [lindex $argv 1]
                puts "$argc"
    2.7、timeout
        设置超时
            set timeout 30
        超时调用
            timeout {send_error "\n处理超时\n";exit 1}
            

    
    2.99 实例代码

 'ChangePasswd')
    {
        (
        /usr/bin/expect <<-EOF
            set timeout 30
            #spawn bash -c "echo 'logoin ${1}'"
            spawn bash -c "ssh ${SYSTEM_USER}@${1} ${3}"
            expect {
                        "*yes/no*" {send "yes\r";exp_continue}
                        "*password*"
                        {
                            send "${SYSTEM_PASSWD}\r"
                            expect {
                                        "*Permission denied, please try again*" {send_user "\n***********root密码错误,退出当前连接!\n\n";exit 1}
                                        "*password*"
                                        {
                                            send "${SYSTEM_PASSWD_NEW}\r"
                                            expect    "*password*" {send "${SYSTEM_PASSWD_NEW}\r"}
                                        }
                                    }
                        }
                    }
            #send "exit\r\r"
            expect eof
        EOF
        )
        #/dev/null 2>&1        
    }

  • 3、关于expect
	3.1	 关于expect: spawn id exp4 not open 报错
		要判断完整,比如下方如果只判断密码错误,就会导致匹配超时
		这里再匹配一个无任何输出的情况,注意" " 中间是空格
		send "${SYSTEM_PASSWD}\r"
							expect {
										"*Permission denied, please try again*" {send_user "\n***********root密码错误,退出当前连接!\n\n";exit 1}
										" " {send_user "\n获取成功\n"}  
												# 用于通配匹配, 如果不加这个匹配,上面单独一行时会匹配超时,对于没有空格输出的命令还是会报错,怎么处理呢?
												# 不能使用"*"通配
												#导致expect匹配超时报错expect: spawn id exp4 not open
												#while executing
												#"expect eof"
									}

10、实例代码

#!/bin/bash
# Function: 对远程服务器执行命令、mysql、systemcmd
# Author: ls
# Date:2023-04-27

SYSTEM_USER='root'
SYSTEM_PASSWD='111'
SYSTEM_PASSWD_NEW='2222'

#========== Servers list===============

server_list=(
'2 192.168.100.110 S1 code1 22' '3 192.168.100.21 S2 code2 22' '4 192.168.100.11 S3 code3 22'
)
#===========================================system control===========================================================
function SYSTEM_CHECK_TOOLS_expect(){
    echo "check expect install ...."
    if type expect >/dev/null 2>&1;then
        echo .
        echo "expect has been installed ...."
        echo .
    else
        {
        echo "expect not install,install expect now ..."
        echo "*************************"
        echo "============================"
        echo "Install Tool expect online"
        echo "============================"
        sudo apt --fix-broken install -y
        sudo apt-get install expect -y || exit 0
        }
    fi
}

# ssh 登录函数,使用expect 交互
# $1 远程服务器地址   $2 选项     $3 需要执行的命令
function SYSTEM_COMMAND_remote_ssh_logoin_runcmd()
{
    if [ $# != 3 ];then
    {
        echo '参数错误,exit;'
        exit
    }
    fi
    
    case ${2} in
    'ChangePasswd')
    {
        (
        /usr/bin/expect <<-EOF
            set timeout 30
            #spawn bash -c "echo 'logoin ${1}'"
            spawn bash -c "ssh ${SYSTEM_USER}@${1} ${3}"
            expect {
                        "*yes/no*" {send "yes\r";exp_continue}
                        "*password*"
                        {
                            send "${SYSTEM_PASSWD}\r"
                            expect {
                                        "*Permission denied, please try again*" {send_user "\n***********root密码错误,退出当前连接!\n\n";exit 1}
                                        "*password*"
                                        {
                                            send "${SYSTEM_PASSWD_NEW}\r"
                                            expect    "*password*" {send "${SYSTEM_PASSWD_NEW}\r"}
                                        }
                                    }
                        }
                    }
            #send "exit\r\r"
            expect eof
        EOF
        )
        #/dev/null 2>&1        
    }
    ;;
    
    "shell")
    {
        #(
        /usr/bin/expect <<-EOF
            set timeout 30
            spawn bash -c "(ssh ${SYSTEM_USER}@${1}<${3}|tail -n 5)"
            expect {
                        "*yes/no*" {send "yes\r";exp_continue}
                        "*password*"
                        {
                            send "${SYSTEM_PASSWD}\r"
                            expect {
                                        "*Permission denied, please try again*" {send_user "\n***********root密码错误,退出当前连接!\n\n";exit 1}
                                        " " {send_user "\n获取成功\n"}  
                                                # 用于通配匹配, 如果不加这个匹配,上面单独一行时会匹配超时,对于没有空格输出的命令还是会报错,怎么处理呢?
                                                # 不能使用"*"通配
                                                #导致expect匹配超时报错expect: spawn id exp4 not open
                                                #while executing
                                                #"expect eof"
                                    }
                        }
                    }
            #send "exit\r\r"
            expect eof
        EOF
        #)2>>/dev/null
        #>>/dev/null 2>&1    
        #>>/tmp/serinfo.md 2>&1    
    }
    ;;
    
    'cmd')
    {
        #(
        /usr/bin/expect <<-EOF
            set timeout 20
            spawn bash -c "ssh ${SYSTEM_USER}@${1} ${3}"
            expect {
                "*yes/no*" {send "yes\r";exp_continue}
                "*password*"
                        {
                            send "${SYSTEM_PASSWD}\r"
                            expect {
                                        "*Permission denied, please try again*" {send_user "\n***********root密码错误,退出当前连接!\n\n";exit 1}
                                        " " {send_user "\n获取成功\n"}  
                                    }
                        }
                    }
            send "\r\r"
            expect eof
        EOF
        #)>>/dev/null 2>&1        
    }
    ;;
    
    *)
    {
        echo 'Usege:'
        echo '# $1 远程服务器地址   $2 选项     $3 需要执行的命令'
        echo 'SYSTEM_COMMAND_remote_ssh_logoin_runcmd [ip] [OPTION] [cmd]'
        echo 'OPTION:'
        echo '      ChangePasswd        修改账户密码,        EXP: SYSTEM_COMMAND_remote_ssh_logoin_runcmd ChangePasswd 'sudo passwd root' '
        echo '      shell               远程执行脚本,        EXP:SYSTEM_COMMAND_remote_ssh_logoin_runcmd shell ls_server_info.sh'
        echo '      cmd                 远程执行普通命令,    EXP:SYSTEM_COMMAND_remote_ssh_logoin_runcmd 'df -h''
        echo '      ...                 待实现...'
    }
    ;;
    
    esac
}

# 主函数
# $1 远程服务器地址   $2 需要执行的命令
function SYSTEM_COMMAND_remote_ssh()
{
    SYSTEM_CHECK_TOOLS_expect
    for ((i=0;i<${#server_list[@]};i++))
    do {
            array_tmp=(${server_list[i]})
            echo "============== ${array_tmp[0]} - ${array_tmp[2]}====================="
            #SYSTEM_COMMAND_remote_ssh_logoin_runcmd ${array_tmp[1]} ChangePasswd "sudo passwd root"
            #SYSTEM_COMMAND_remote_ssh_logoin_runcmd ${array_tmp[1]} cmd 'df -h'
            SYSTEM_COMMAND_remote_ssh_logoin_runcmd ${array_tmp[1]} shell 'ls_server_info.sh'
        }
    done
}
#===========================================system control===========================================================

#===========================================function main ===========================================================
function MAIN()
{
    #MYSQL_LS_DB_GET_DATA
    SYSTEM_COMMAND_remote_ssh
}

MAIN
#===========================================function main ===========================================================


exit 0

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值