人工发出指令控制程序的运行,程序在接收到人工相应的指令后,做出相应的反应
程序按照编写好的运行方式进行指定指令的动作,在这过程中,不需要人工进行指定操作,自动化完成
(1)使用I/O重定向的方式将命列表提供给交互式程序
(2)口标准输入的一种替代品
(3)语法格式
命令 <<标记
…
…
标记
[root@test1 opt]# read i < zjf,123
> EOF
[root@test1 opt]# echo $i
zjf,123
[root@test1 opt]# useradd zhangsan
[root@test1 opt]# passwd zhangsan < 123
> 123
> EOF
更改用户 zhangsan 的密码 。
新的 密码:无效的密码: 密码少于 8 个字符
重新输入新的 密码:passwd:所有的身份验证令牌已经成功更新。
[root@test1 opt]# cat < this is an apple
> yes
> EOF
this is an apple
yes
[root@test1 opt]# cat <test5.txt
> this is an apple
> yes
> EOF
[root@test1 opt]# cat test5.txt
this is an apple
yes
[root@test1 opt]# vim zz.sh
[root@test1 opt]# cat zz.sh
file="xx.txt"
i="banana"
cat > $file <
[root@test1 opt]# vim qq.sh
[root@test1 opt]# cat qq.sh
var="GREAT! i am going to school!"
cat > rr.txt <
[root@test1 opt]# vim ztfz.sh
[root@test1 opt]# cat ztfz.sh
var="GREAT! i am going to school!"
myvar=$(cat <
[root@test1 opt]# vim ztfz.sh
[root@test1 opt]# cat ztfz.sh
var="GREAT! i am going to school!"
myvar=$(cat <<'EOF'
today is monday
$var
EOF
)
echo $myvar
[root@test1 opt]# sh ztfz.sh
today is monday $var
tab键的空可以去掉
空格不可以去掉
[root@test2 ~]# cat qd.sh
cat <<-'EOF'
zjf
123
EOF
[root@test2 ~]# sh qd.sh
zjf
123
[root@test2 ~]# cat qd.sh
: <<-'EOF'
zjf
123
EOF
[root@test2 ~]# sh qd.sh
[root@test2 ~]#
(1)建立在tcl之上的一个工具
(2)用于进行自动化控制和测试
(3)解决shel脚本中交互相关的问题
[root@test2 ~]# rpm -q expect
未安装软件包 expect
[root@test2 ~]# yum -y install expect
expect 脚本中首先引入文件,表明使用的是哪一个 shell。#!/usr/bin/expectchmod 777 xxx. sh
bash sh
./
spawn 后面通常跟一个Linux执行命令,表示开启一个会话、启动进程,并跟踪后续交互信息。例: spawn passwd root
判断上次输出结果中是否包含指定的字符串,如果有则立即返回,否则就等待超时时间后返回;只能捕捉由spawn启动的进程的输出:用于接收命令执行后的输出,然后和期望的字符串匹配.
向进程发送字符串,用于模拟用户的输入;该命令不能自动回车换行,
一般要加\r (回车) 或者\n
例:
方式一:
expect"密码”{send “abc123\r”} #同一行send部分要有{}
方式二:
expect"密码”
send “abc123\r” #换行send部分不需要有{ }
方式三:
expect支持多个分支
expect #只要匹配了其中一个情况,执行相应的send语句后退出该expect语句
{
“密码1” {send “abc123\r”}
“密码2” {send “123456\r”}
“密码3” {send “123123\r”}
}
表示交互结束,等待执行结束,退回到原用户,与spawn对应。比如切换到root用户,expect脚本默认的是等待10s,当执行完命令后,默认停留10s后,自动切回了原用户。
执行完成后保持交互状态,把控制权交给控制台,会停留在目标终端而不会退回到原终端,这个时候就可以手工操作了,interact后的命令不起作用,比如interact后添加exit,并不会退出root用户而如果没有interact则登录完成后会退出,而不是留在远程终端上。使用interact会保持在终端而不会退回到原终端,比如切换到root用户,会一直在root用户状态下:比如ssh到另一服务器,会一直在目标服务器终端,而不会切回的原服务器。
注意: expect_eof 与 interact 只能二选一。
expect 默认的超时时间是 10 秒,通过 set 命令可以设置会话超时时间,若不限制超时时间则应设置为-1。
例: set timeout 5
exp_continue 附加于某个 expect 判断项之后,可以使该项被匹配后,还能续匹配该 expet 判断语句内的其他项。exp continue 类似于控制语句中的 continue 语句。表示允许 expect 继续向下执行指令。例如:下例将判断交互输出中是否存在 yes/no 或 password。如果匹配 yes/no 则输出 yes 并再次执行判断:如果匹配password 则输出 abc123 并结束该段 expect 语句。
send_user 表示回显命令,相当于 echo。打印的功能
expect 脚本可以接受从bash命令行传递的参数,使用[lindex Sargv n]获得。其中n从0开始,分别表示第一个,第二个,第三个…参数。类似与位置变量,用法相同
例:
set hostname [lindex Sargv 0] ——————相当子 hostname=S1
set password [lindex Sarqy 1]————————相当于 password-S2
注意: expect脚本不能通过bash、 source、来执行(因为这三种方式是调用shell解释器),只能通过绝对路径或相对路径来执行。
[root@test1 opt]# vim passwd.sh
#!/usr/bin/expect #expect的路径指定使用expect编译器
set timeout 3 #设置退时间
spawn passwd zjf #开启修改密码
expect "新的 密码:" #捕获
send "123\r" #设置密码
expect "重新输入新的 密码:" #捕获
send "123\r" #设置密码
expect eof #退出
[root@test1 opt]# chmod 777 passwd.sh
[root@test1 opt]# ./passwd.sh
spawn passwd zjf
更改用户 zjf 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
expect eof 结束语
vim chuancan.sh
#!/usr/bin/expect
set timeout 3
set username [lindex $argv 0] #相当于$1
set password [lindex $argv 1] #相当于$2
spawn su - $username
expect "Password:"
send "$password\r"
expect "*]$" #判断捕获 * 表示所有]前的所有
send_user "ok"
expect eof #跳出当前终端回到之前终端
[root@test1 opt]# chmod 777 chuancan.sh
[root@test1 opt]# su - zjf
上一次登录:四 6月 8 19:28:03 CST 2023pts/7 上
[zjf@test1 ~]$ cd /opt/
[zjf@test1 opt]$ ./chuancan.sh lisi 123
spawn su - lisi
密码:
上一次登录:四 6月 8 19:30:44 CST 2023pts/7 上
[lisi@test1 ~]$ ok[zjf@test1 opt]$
interact 结束语
[root@test1 opt]# vim chuancan.sh
#!/usr/bin/expect
set timeout 3
set username [lindex $argv 0]
set password [lindex $argv 1]
spawn su - $username
expect "Password:"
send "$password\r"
expect "*]$"
send_user "ok"
interact
[root@test1 opt]# chmod 777 chuancan.sh
[root@test1 opt]# su - lisi
[lisi@test1 ~]$ cd /opt/
[lisi@test1 opt]$ ./chuancan.sh zjf 123
spawn su - zjf
密码:
上一次登录:四 6月 8 19:39:13 CST 2023pts/8 上
最后一次失败的登录:四 6月 8 19:43:54 CST 2023pts/2 上
最有一次成功登录后有 2 次失败的登录尝试。
[zjf@test1 ~]$ ok
[zjf@test1 ~]$
[root@test1 opt]# vim qtmo.sh
#!/bin/bash
user=$1
passwd=$2
useradd $1
/usr/bin/expect <<-EOF
spawn passwd $user
expect "新的 密码:"
send "${passwd}\r"
expect "重新输入新的 密码:"
send "${passwd}\r"
expect eof
EOF
[root@test1 opt]# chmod 777 qtmo.sh
[root@test1 opt]# ./qtmo.sh ff 123 也可以用sh qtmo.sh dd 123方式
spawn passwd ff
更改用户 ff 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
[root@test1 opt]# vim zdssh.sh
#!/usr/bin/expect
set ip 192.168.198.12
set user root
set passwd 000000
set timeout 5
spawn ssh $user@$ip
expect {
"yes/no" {send "yes\n";exp_continue}
"password" {send "${passwd}\n"}
}
interact
[root@test1 opt]# chmod 777 zdssh.sh
[root@test1 opt]# ./zdssh.sh
spawn ssh [email protected]
[email protected]'s password:
Last failed login: Thu Jun 8 22:16:50 CST 2023 from 192.168.198.11 on ssh:notty
There were 4 failed login attempts since the last successful login.
Last login: Thu Jun 8 22:01:11 2023 from 192.168.198.1
[root@test2 ~]# #如想退出终端在脚本命令中将interact修改为expect eof
[root@test1 opt]# vim ssh.sh
#!/usr/bin/expect
set timeout 5
set hostname [lindex $argv 0]
set password [lindex $argv 1]
spawn ssh $hostname
expect {
"connection refused" {send_user "ssh访问被拒绝\n"}
"No route to host" {send_user "主机名/ip地址有误\n"}
"yes/no" {send "yes\n";exp_continue}
"password" {send "$password\n"}
}
interact
[root@test1 opt]# chmod 777 ssh.sh
[root@test1 opt]# ./ssh.sh 192.168.198.14 123 #未开启的终端地址会直接报错
spawn ssh 192.168.198.14
ssh: connect to host 192.168.198.14 port 22: No route to host
主机名/ip地址有误
使输入密码的时候也免交互输入登录
[root@test1 ~]# vim fdisk.sh
#!/bin/bash
/usr/bin/expect <<-EOF
set timeout 5
spawn fdisk /dev/sdb
expect {
"命令(输入 m 获取帮助):" { send "n\n";exp_continue}
"Select (default p): " {send "p\n";exp_continue}
"分区号 (1-4,默认 1):" {send "\n";exp_continue}
"起始 扇区 (2048-41943039,默认为 2048):" {send "\n";exp_continue}
"Last 扇区*" {send "+10G\nw\n";exp_continue}
expect eof
}
EOF
mkfs.xfs -f /dev/sdb1
mkdir /data
mount /dev/sdb1 /data
[root@test1 ~]# ./fdisk.sh