expect 解决linux命令交互问题
23.1 expect使用
TCL(Tool command language)是一种类似shell脚本的语言,你可以使用它来完成许多操作。expect是从它发展出来的。如果你想要写一个能够自动处理输入输出的脚本(如向用户提问并且验证密码)又不想面对C或者Perl,那么expect是你的最好的选择
expect是在tcl基础上创建起来的,它还提供了一些tcl所没有的命令,它可以用来做一些linux下无法做到交互的一些命令操作
23.1.1 安装
[root@xuegod63 ~]# yum -y install expect
23.1.2 使用
使用expect创建脚本的方法
1)定义脚本执行的shell
#!/usr/bin/expect
这里定义的是expect可执行文件的链接路径(或真实路径),功能类似于bash等shell功能
2)设置变量
语法:set 变量名 变量值
set timeout 30
设置超时时间,单位是秒,如果设为timeout -1 意为永不超时
3)spawn
spawn 是进入expect环境后才能执行的内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。不能直接在默认的shell环境中进行执行主要功能,它主要的功能是给ssh运行进程加个壳,用来传递交互指令。spawn主要作用是产生一个会话,然后才能执行对应的expect命令。
4)expect
这里的expect同样是expect的内部命令
主要功能:判断输出结果是否包含某项字符串,没有则立即返回,否则就等待一段时间后返回,等待时间通过timeout进行设置
5)send
执行交互动作,将交互要执行的动作进行输入给交互指令
命令字符串结尾要加上"\r 表示回车;\t表示制表符;\n表示换行",如果出现异常等待的状态可以进行核查
6)exp_continue
如果需要做多次关键字匹配,继续执行接下来的交互操作
7)interact
执行完后保持交互状态,把控制权交给控制台;如果不加这一项,交互完成会自动退出
8)$argv $argc
expect 脚本可以接受从bash传递过来的参数,可以使用 [lindex $argv n]获得,n从0开始,分别表示第一个,第二个,第三个……参数
$argc表示传参的个数,可以使用if条件语句,语法如下:
if (条件表达式) { 命令 }
9)expect eof
执行完expect命令后,直接退回到本地shell,不在远程停留。作用和interact相反。
10) if语句的语法
if { 条件表达式 } {
指令
}
或者
if { 条件表达式 } {
指令
}
else {
指令
}
注意:if关键字后面要有空格,else关键字前后要有空格
{条件表达式} 大括号里可以没有空格, 外面前后要有空格
实战:expect实现无交互登录
范例1:
免密码通过SHH登录服务器
#!/usr/bin/expect
spawn ssh root@10.10.30.131 uptime
expect {
"yes/no" { send "yes\r";exp_continue }
"password" { send "123456\r" }
}
expect eof
[root@xuegod1603 days5]# expect exp_1.exp
spawn ssh root@10.10.30.131 uptime
root@10.10.30.131's password:
20:57:21 up 2:09, 1 user, load average: 0.03, 0.01, 0.00
范例2:
免密登录服务后创建一些文件目录
#!/usr/bin/expect
set IPaddr 10.10.30.131
set PASS 123456
spawn ssh root@$IPaddr
expect {
"yes/no" { send "yes\r";exp_continue }
"password" { send "$PASS\r" }
}
expect "#"
send "touch /tmp/{a..d}.txt\r"
send "cp /etc/hosts /tmp\r"
send "mkdir /tmp/xuegod\r"
expect eof
[root@xuegod1603 days5]# expect exp_2.exp
spawn ssh root@10.10.30.131
The authenticity of host '10.10.30.131 (10.10.30.131)' can't be established.
RSA key fingerprint is SHA256:vt50JwJhiyX4MNqfLZGNm36TBpI/WgFg3R3CKurtmTU.
RSA key fingerprint is MD5:93:65:a4:58:55:2f:36:47:10:0b:b8:c8:90:eb:6a:8c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.10.30.131' (RSA) to the list of known hosts.
root@10.10.30.131's password:
Last login: Mon Apr 2 20:35:54 2018 from 10.10.30.139
[root@panda63 ~]# touch /tmp/{a..d}.txt
[root@panda63 ~]# cp /etc/hosts /tmp
[root@panda63 ~]# mkdir /tmp/xuegod
[root@panda63 ~]# [root@xuegod1603 days5]#
[root@xuegod1603 days5]#
范例3:
自动处理read交互
#!/bin/bash
read -p "pls input your username:" name
read -p "pls input your password:" pass
read -p "pls input your email:" mail
echo -n "your name is $name ,"
echo -n "your password is $pass ,"
echo "your email is $mail"
[root@x112 test]# cat expxinxi.exp
#!/usr/bin/expect
spawn /bin/sh xinxi.sh
set username feng
set password 123
set email feng@neusoft.com
expect {
"username" {exp_send "${username}\r";exp_continue}
"password" {send "${password}\r";exp_continue}
"email" {exp_send "${email}\r"}
}
expect eof
[root@x112 test]# expect expxinxi.exp
spawn /bin/sh xinxi.sh
pls input your username:feng
pls input your password:123
pls input your email:feng@neusoft.com
your name is feng ,your password is 123 ,your email is feng@neusoft.com
[root@x112 test]#
#!/usr/bin/expect
#set timeout 5
spawn /bin/sh read.sh
expect {
"username" {send "xuegod\r";exp_continue}
"password" {send "123456\r";exp_continue}
"directory" {send "/mnt\r"}
#timeout {send “---------byby---------”}
}
expect eof
[root@xuegod1603 days5]# expect exp_3.exp
spawn /bin/sh read.sh
Please input your username: xuegod
Please input your password:123456
Please input your directory: /mnt
Your name: xuegod
Your password: 123456
INPUT A directory; /mnt
范例4:
使用set自定义变量
#!/usr/bin/expect
set account root
set ip 192.168.0.101
set pass 1
spawn ssh $account@$ip
expect {
"yes/no" { send "yes\r";exp_continue }
"password" { send "$pass\r" }
}
expect {
"#" {
send "mkdir /abcd\r";
send "cd /abcd\r";
send "touch {a..d}.txt\r";
send "ls /abcd\r"
}
}
expect eof
[root@x112 test]# !echo
echo > /root/.ssh/known_hosts
[root@x112 test]# expect exp_1.exp
spawn ssh root@192.168.0.101
The authenticity of host '192.168.0.101 (192.168.0.101)' can't be established.
ECDSA key fingerprint is SHA256:S/ojuQNKfl5/Mg+QzNACIiU3KwbSfH6xIG/GkNQgiro.
ECDSA key fingerprint is MD5:46:bf:5d:65:a3:e1:f3:82:76:f1:7a:ab:7f:58:1d:75.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.0.101' (ECDSA) to the list of known hosts.
root@192.168.0.101's password:
Last login: Sun Nov 1 19:40:46 2020 from 192.168.0.112
[root@x101 ~]# mkdir /abcd
mkdir: cannot create directory ‘/abcd’: File exists
[root@x101 ~]# cd /abcd
[root@x101 abcd]# touch {a..d}.txt
[root@x101 abcd]# ls /abcd
a.txt b.txt c.txt d.txt
[root@x101 abcd]# [root@x112 test]#
[root@x112 test]#
范例5:
对服务器的批量管理
10.10.30.130 rootroot
10.10.30.131 123456
10.10.30.132 xxxxxx
[root@xuegod1603 days5]# cat exp_4.exp
#!/usr/bin/expect
set ipaddr [lindex $argv 0]
set passwd [lindex $argv 1]
set timeout 30
spawn ssh root@$ipaddr "ls /tmp"
expect {....
"yes/no" {send "yes\r";exp_continue}
"password" {send "$passwd\r"}
}
expect eof
[root@xuegod1603 days5]# cat login.sh
#!/bin/bash
for ip in $(awk '{print $1}' /scripts/days5/ip_pass.txt)
do
pass=$(grep $ip /scripts/days5/ip_pass.txt |awk '{print $2}')
expect /scripts/days5/exp_4.exp $ip $pass
done
[root@xuegod1603 days5]# sh login.sh
spawn ssh root@10.10.30.130 ls /tmp
The authenticity of host '10.10.30.130 (10.10.30.130)' can't be established.
RSA key fingerprint is SHA256:vt50JwJhiyX4MNqfLZGNm36TBpI/WgFg3R3CKurtmTU.
RSA key fingerprint is MD5:93:65:a4:58:55:2f:36:47:10:0b:b8:c8:90:eb:6a:8c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.10.30.130' (RSA) to the list of known hosts.
root@10.10.30.130's password:
etc
keyring-6jHnDq
keyring-EgGnpL
keyring-OoF3sf
keyring-QHI86e
keyring-SWWKRK
keyring-vCIXLB
spawn ssh root@10.10.30.131 ls /tmp
root@10.10.30.131's password:
a.txt
b.txt
c.txt
d.txt
hosts
xuegod
spawn ssh root@10.10.30.132 ls /tmp
ssh: connect to host 10.10.30.132 port 22: No route to host
expect: spawn id exp6 not open
while executing
"expect eof"
(file "/scripts/days5/exp_4.exp" line 10)
范例6:
使用if语句判断脚本传参的个数,不管是否符合都给予提示
#!/usr/bin/expect
if { $argc != 26 } {
puts "bad."
} else {
puts "good."
}
[root@localhost ~]# expect shili.exp
bad.
[root@localhost ~]# expect shili.exp {a..z}
good.