shell编程之Expect免交互
admin
2023-02-25 02:00:05
0

shell编程之Expect免交互

一、前言

​ shell脚本存在的核心意义就在于基于shell命令简化甚至省略可避免的人工操作,通过各种控制流程结构以及正则表达式等方法,逐步实现自动化操作的整个过程,由此也可见,shell并没有面向对象的思想,类似C语言,毕竟C语言是操作系统或者说是内核的核心语言。

​ 所以,语言并无优劣之分,只是每个人使用的习惯与方式不同,换句话说,难易的不是语言,而是思想与突如其来的灵感。

二、Expect概述与安装

Expect概述

​ Expect是建立在TCL基础上的一个工具,Expect是用来进行自动化控制和测试的工具。主要解决shell脚本中不可交互的问题。对于大规模的Linux运维很有帮助。

​ 在Linux运维和开发中,我们经常需要远程登录服务器进行操作,登录的过程是一个交互过程,需要输入yes/no password等信息。为了模拟这种输入,可以使用Expect脚本。

Expect的安装:yum install -y expect

三、基本命令

  1. send:向进程发送字符串,用于模拟用户的输入,但不支持换行 一般需要加上 \r

  2. expect:内部命令

    ​ 判断上次输出结果里是否包含指定的字符串,有则返回,反之就等待超时时间后返回。

    ​ 只能捕捉由spawn启动的进程的输出。

  3. spawn:启动进程,并跟踪后续交互信息。

  4. interact:执行完成后保持交互状态,把控制权交给控制台。

Timeout:指定超时时间,过期则继续执行后续指令

  • 单位是s
  • timeout -1为永不超时
  • 默认情况下timeout 是10s

exp_continue——允许expect继续向下执行指令(比较关键,多次交互)

send_user——回显命令,相当于echo

四、expect语法

expect [选项] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
选项
-c:从命令行执行expect脚本,默认expect是交互地执行的
示例:expect -c 'expect "\n" {send "pressed enter\n"}
-d:可以输出输出调试信息
示例:expect -d ssh.exp

expect最常用的语法(tcl语言:模式-动作)
单一分支模式语法:
expect “hi” {send “You said hi\n"} 匹配到hi后,会输出“you said hi”,并换行,也可以使用\r
多分支模式语法:
expect "hi" { send "You said hi\n" } \ "hehe" { send “Hehe yourself\n" } \ "bye" { send “Good bye\n" }
匹配hi,hello,bye任意字符串时,执行相应输出.等同如下:
expect { "hi" { send "You said hi\n"} "hehe" { send "Hehe yourself\n"} "bye" { send “Good bye\n"} }

五、实例:

1)ssh免交互远程登录

[root@lokott ~]# yum install -y expect
已加载插件:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
...//省略部分
[root@lokott shell]# cat a.sh 
#使用which expect查看其位置
#!/usr/bin/expect
#设置超时时间
    set timeout 20
    log_file test.log
    log_user 1
#变量定义
    set hostname [lindex $argv 0]
    set passwd [lindex $argv 1]
#启动进程,spawn监控
    spawn ssh root@$hostname
#匹配条件
    expect {
        "(yes/no)"
#exp_continue表示继续向下匹配
        {send "yes\r";exp_continue}  
        "*password"
        {send "$passwd\r"}
}
#转交权限给控制台
interact 

[root@lokott shell]# ./a.sh 192.168.68.129 123456   //第一次登录
spawn ssh root@192.168.68.129
The authenticity of host '192.168.68.129 (192.168.68.129)' can't be established.
ECDSA key fingerprint is SHA256:k/6W9M/dgxVrbMgSx9nIFPGfVgUfLMoIb27ys9ZF+LM.
ECDSA key fingerprint is MD5:26:dd:06:b3:32:bd:d6:a3:2f:7c:66:7d:b9:c0:4b:c4.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.68.129' (ECDSA) to the list of known hosts.
root@192.168.68.129's password: 
Last login: Wed Dec  4 10:24:33 2019 from 192.168.68.1
[root@localhost ~]# exit
登出
Connection to 192.168.68.129 closed.
[root@lokott shell]# ./a.sh 192.168.68.129 123456   //第二次登录上一次登录需要的秘钥已经保存
spawn ssh root@192.168.68.129
root@192.168.68.129's password: 
Last login: Wed Dec  4 10:29:42 2019 from 192.168.68.130
[root@localhost ~]# exit
登出
Connection to 192.168.68.129 closed.

上述演示的是直接使用expect脚本实现ssh远程登录的操作过程,而expect脚本也可以被嵌入到普通的脚本文件中,下面给出具体演示:

[root@lokott shell]# cat b.sh 
#嵌入expect执行实现免交互登录
#!/bin/bash
#定义普通变量,在该shell脚本中始终有效
hostname=$1
passwd=$2
#嵌入写入expect脚本内容??实现免交互的具体内容
/usr/bin/expect<<-EOF
spawn ssh root@$hostname
expect {
    "(yes/no)"
    {send "yes\r";exp_continue}
    "*password"
    {send "$passwd\r";}
}
#下两行是为了返回本地控制台的操作演示
expect "*]#"
send "exit\r"
expect eof
EOF
#注意EOF的前后都不可以有空格!!!
[root@lokott shell]# ./b.sh 192.168.68.129 123456
spawn ssh root@192.168.68.129
root@192.168.68.129's password: 
Last login: Wed Dec  4 12:22:23 2019 from 192.168.68.130
[root@localhost ~]# exit
登出
Connection to 192.168.68.129 closed.

推荐使用这种方式,因为在实际使用中一般都是在普通脚本中使用expect的,所有嵌入写入比较方便,比较常用!

直接使用expect免交互的完整脚本如下,有兴趣可以试着改为嵌入写入的代码:

[root@lokott shell]# cat ssh.sh 
#!/usr/bin/expect
set timeout 5
set hostname [lindex $argv 0]
set password [lindex $argv 1]
spawn ssh root@$hostname
expect {
"No route to host" exit
"Invalid argument" exit
"Connection refused" exit
"Name or service not known" exit
"to continue" {send "yes\r";exp_continue}
"password:" {send "$password\r"}
}
interact
exit
[root@lokott shell]# ./ssh.sh 192.168.68.133 123456  //服务器非在线
spawn ssh root@192.168.68.133
ssh: connect to host 192.168.68.133 port 22: No route to host
[root@lokott shell]# ./ssh.sh  123456    //参数输入错误
spawn ssh root@123456
ssh: connect to host 123456 port 22: Invalid argument
[root@lokott shell]# ./ssh.sh 192.168.68.129 123456   //正常登录
spawn ssh root@192.168.68.129
root@192.168.68.129's password: 
Last login: Wed Dec  4 15:20:51 2019 from 192.168.68.130
[root@localhost ~]# 

2)添加用户与用户密码的免交互操作过程

[root@lokott shell]# cat c.sh 
#!/bin/bash
username=$1
password=$2
useradd $1
[ $? -eq 0 ]&&echo ||exit 1
/usr/bin/expect<<-EOF
spawn passwd ${username}
expect {
    "密码:"
    {send  "${password}\r";exp_continue}

    "密码:"
    {send  "${password}\r";}

}
EOF

tail -1 /etc/shadow|awk -F: '{print $1,$2}'
userdel -r $1
#执行结果如下
[root@lokott shell]# ./c.sh zhazhahui 123456

spawn passwd zhazhahui
更改用户 zhazhahui 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
zhazhahui $6$k.MdzCd3$XMUGf5XQV4sE5RJqcwdEoOkd8UVgWtwcguzi6Md5yXcagYvgyE8GmCjzjxkEB5rXR.IRG9j49c36amzkDIe5l1

六、总结

​ 本文主要介绍了expect实现免交互的作用以及结合实际案例讲解其两种使用方式(直接和嵌入)的具体操作过程。

​ 过程主要分为:基本变量定义(timeout最好最先设置)——spawn启动跟踪——expect匹配——interact交付控制权(没有会退出)或者expect eof 结束expect匹配。

​ 务必结合上述的案例自己多使用体会理解!

相关内容

热门资讯

雷达、机库、营房、燃料库、飞机... 据《华盛顿邮报》5月6日报道,通过卫星影像分析发现,自2月28日战事爆发以来,伊朗空袭已在中东美军军...
从买买买到租租租,“租用一代”... “五一”假期还在路上,年轻人已经“租”起来了。 “租三天,不到300块钱。”五一放假前一周,清清已给...
【品牌】摩托罗拉大折叠屏新机定... 此前联想预热将于5月19日19点举行联想天禧AI一体多端全场景新品超能之夜活动,届时将带来多款新品,...
常州欣隽益取得接线端子用快速冲... 国家知识产权局信息显示,常州欣隽益科技有限公司取得一项名为“接线端子用快速冲切装置”的专利,授权公告...
美媒:特朗普在结束伊朗战争问题... 据“国会山”网站5月6日报道,周二晚间,美国总统特朗普突然宣布终止旨在打破伊朗对霍尔木兹海峡掌控的军...
和创硅材料取得熔融石英制品擦洗... 国家知识产权局信息显示,东海县和创硅材料有限公司取得一项名为“一种熔融石英制品的擦洗脱泥装置”的专利...
美商务部长再就爱泼斯坦案接受国... 5月6日,美国商务部长卢特尼克“自愿”就其与爱泼斯坦的关系接受美国国会众议院监督与政府改革委员会的问...
“五一”小长假黄金零售市场新变... 【大河财立方 记者 孙凯杰】 “五一”小长假,黄金价格出现一波短暂调整,线下黄金零售市场热度如何?5...
以军3周来首次袭击黎巴嫩首都 据以色列总理内塔尼亚胡和国防部长卡茨当地时间5月6日晚发表的联合声明,以军当天对黎巴嫩首都贝鲁特南郊...
东莞移动:5G-A智擎护航, ... “五一”期间,松山湖草莓音乐节、广东国际汽车展示交易会·春季、2026茶园游会田园文化美食节、大岭山...