expect是什么
expect是一个免费的编程工具,用来实现自动的交互式任务,而无需人为干预。说白了,expect就是一套用来实现自动交互功能的软件。
在实际工作中,我们运行命令、脚本或程序时,这些命令、脚本或程序都需要从终端输入某些继续运行的指令,而这些输入都需要人为的手工进行。而利用expect,则可以根据程序的提示,模拟标准输入提供给程序,从而实现自动化交互执行。这就是expect!!!
在使用expect时,基本上都是和以下四个命令打交道:
send
用于向进程发送字符串
expect
从进程接收字符串
spawn
启动新的进程
interact
允许用户交互
- send命令接收一个字符串参数,并将该参数发送到进程。
- expect命令和send命令相反,expect通常用来等待一个进程的反馈,我们根据进程的反馈,再发送对应的交互命令。
- spawn命令用来启动新的进程,spawn后的send和expect命令都是和使用spawn打开的进程进行交互。
- interact命令用的其实不是很多,一般情况下使用spawn、send和expect命令就可以很好的完成我们的任务;但在一些特殊场合下还是需要使用interact命令的,interact命令主要用于退出自动化,进入人工交互。比如我们使用spawn、send和expect命令完成了ftp登陆主机,执行下载文件任务,但是我们希望在文件下载结束以后,仍然可以停留在ftp命令行状态,以便手动的执行后续命令,此时使用interact命令就可以很好的完成这个任务。
声明expect脚本
查看expect
脚本的路径,然后在expect脚本文件第一行声明,类似bash
脚本
#!/usr/bin/expect
自动ssh登录demo
#!/usr/tcl/bin/expect
set timeout 30 #设置超时时间
set host "101.200.241.109" #设置变量
set username "root" #设置变量
set password "123456" #设置变量
spawn ssh $username@$host #给ssh运行进程加个壳,用来传递交互指令
expect "*password*" {send "$password\r"} #期待上一行命令返回的结果中包含password字符串,*类似redis中keys寻找key,匹配任务数量的任意字符
interact #没有这一句登录完成后会退出,而不是留在远程终端上
脚本中的各项参数解释
set timeout 30
设置超时时间,单位为秒,默认情况下是10秒set host "101.200.241.109"
设置变量spawn ssh $username@$host
是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的
。它主要的功能是给ssh运行进程加个壳,用来传递交互指令expect "*password*" {send "$password\r"}
这里的expect
也是expect
的一个内部命令,这个命令的意思是判断上次输出结果里是否包含“password”的字符串,如果有则立即返回
;否则就等待一段时间后返回
,这里等待时长就是前面设置的30秒
,这里这个expect看起来似乎是支持正则的,其实就是期待上一行命令的返回结果是不是预期的,是预期的时候才执行下一步;然后后面跟着的{send "$password\r"}
意味着,上一行命令返回包含password
的字符串的时候,去执行.类似if
.最后有一个\r
不要忘记了,意味的命令输入完之后的回车.interact
执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上
。
expect脚本传参demo
#!/usr/bin/expect
if {$argc < 3} {
puts "Usage:cmd <host> <username> <password>"
exit 1
}
set timeout -1
set host [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]
spawn ssh $username@$host
expect "*password*" {send "$password\r"}
interact
脚本中的参数解释
在expect
中,$argc
表示参数个数,而参数值存放在$argv
中,比如取第一个参数就是[lindex $argv 0]
,以此类推。
但是expect中发送执行脚本命令给远端服务器的时候会发现,被执行的脚本中的相对路径会报不存在.需要改成绝对路径(全路径).这个时候就需要在远端服务器上ssh执行代码块了
expect参考了大佬的文章
https://www.jianshu.com/p/bbe9949e2562
ssh
在远端服务器上执行脚本或者shell
命令代码块
前提需要配置ssh免密登录,这个可以参考我另一篇博文
https://blog.csdn.net/weixin_43944305/article/details/103288482
如果是简单执行几个命令,则:
ssh user@remoteIp "cd /home ; ls;"
几个注意的点:
双引号
,必须有。如果不加双引号,第二个ls命令在本地执行分号
,两个命令之间用分号隔开
如果要执行的命令比较多,可能一行写不下,这个事就可以使用<<
来达到执行代码块的目的了
sh脚本执行代码块或者执行远程服务器上的脚本demo
- 事先最好使用
ssh公私钥
实现免密ssh登录
,具体可以参考我另一篇文章https://blog.csdn.net/weixin_43944305/article/details/103288482 - 执行的命令在
<< gg
和gg
之间,这个gg
可以自定义 > /dev/null 2>&1
重定向目的在于不显示远程的输出了,/dev/null
这个设备,是linux
中黑洞设备,什么信息只要输出给这个设备,都会给吃掉;2>&1
代表将错误输出2绑定给正确输出1
,然后将正确输出发送给/dev/null
设备- 在结束前,加
exit
退出远程节点
#!/bin/bash
ssh user@remoteNode > /dev/null 2>&1 << gg
cd /home
touch abcdefg.txt
./xxx.sh & #有运行权限的话直接执行; '&'类似nohup的'&'使脚本在后台自动运行
exit
gg
echo done!