文章目录
一、Here Document免交互
1.概述
–使用I/O重定向的方式将命令列表提供给交互式程序,比如 ftp、cat 或 read 命令。
–标准输入的一种替代品
2.基本语法格式
特殊字符“<<”在标记和命令之前,这样做的目的是将命令块的输出重定向到程序或命令的 stdin。
标记的选择要确保不会出现在其他地方,避免出现混淆;
两个标记之间的内容被当做是一个文件并用作“命令”的标准输入。
另外 Here Document 也可以与非交互式程序和命令一起使用。
命令 <<标记
...
...
标记
3.使用注意事项
标记可以使用任意的合法字符
结尾的标记一定要顶格写,前面不能有任何字符
结尾的标记后面也不能有任何字符(包括空格)
开头的标记前后的空格会被省略
4.示例
1.直接修改密码
[root@yzq mnt]#passwd wangwu <<EOF
> 123456
> EOF
更改用户 wangwu 的密码 。
新的 密码:无效的密码: 密码少于 8 个字符
重新输入新的 密码:密码更改取消。
新的 密码:密码更改取消。
新的 密码:密码更改取消。
passwd: 已经超出服务重试的最多次数
2.给变量赋值
[root@yzq sh]#read a <<EOF
> 8
> EOF
[root@yzq sh]#echo $a
8
3.整体赋值给变量,用echo将变量值打印出来
[root@yzq sh]#sh 1.sh
hello bucuo
[root@yzq sh]#cat 1.sh
#!/bin/bash
nihao=$(cat <<EOF
hello
bucuo
EOF
)
echo $nihao
4.关闭变量替换的功能
[root@yzq sh]#a=10
[root@yzq sh]#cat <<'EOF'
> 15
> $a
> EOF
15
$a
5.忽略制表符
EOF前面添加“-”能够去掉行首的tab制表符,显示出的内容就会顶格显示
[root@yzq sh]#sh 2.sh
hello
nihao
[root@yzq sh]#cat 2.sh
#!/bin/bash
cat <<EOF
hello
nihao
EOF
[root@yzq sh]#vim 2.sh
[root@yzq sh]#sh 2.sh
hello
nihao
[root@yzq sh]#cat 2.sh
#!/bin/bash
cat <<-EOF
hello
nihao
EOF
6.多行注释
Bash 的默认注释是“#”,该注释方法只支持单行注释,在 Shell 脚本的工作中,“#”右侧的任何字符串,bash 都会将其忽略。
“ : ”代表什么都不做的空命令。中间标记区域的内容不会被执行,会被bash 忽略掉,因此可达到批量注释的效果。
[root@yzq sh]#sh 3.sh
123
[root@yzq sh]#cat 3.sh
#!/bin/bash
<<hl
cat <<-EOF
123
321
EOF
hl
echo 123
二、Expect 免交互
expect 是由Don Libes基于Tcl(Tool Command Language )语言开发的,主要应用于自动化交互式操作的场景,是一个免费的编程工具,用来实现自动的交互式任务,而无需人为干预。说白了,expect就是一套用来实现自动交互功能的软件。
1、概述
建立在tcl之上的一个工具
用于进行自动化控制和测试
解决shell脚本中交互相关的问题
2、环境安装
expect 并非是 shell 能够解释的,所以想要执行它来完成你的脚本,你需要先安装两个软件包,当然,在使用yum的情况下,我们执行这条命令就可以了
[root@yzq sh]#yum -y install expect
已加载插件:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* base: mirrors.aliyun.com
* extras: mirrors.ustc.edu.cn
* updates: mirrors.aliyun.com
软件包 expect-5.45-14.el7_1.x86_64 已安装并且是最新版本
无须任何处理
3、基本命令
3.1 脚本解释器
expect 脚本中首先引入文件,表明使用的是哪一个shell
#!/usr/bin/expect
3.2expect(捕捉)
判断上次输出结果是否包含指定的字符串,如果有则立即返回,否则就等待超时时间返回
只能捕捉由spawn启动的进程的输出
用于接收命令执行后的输出,然后和期望的字符串匹配
3.3spawn(跟踪)
spawn 后面通常跟一个Linux执行命令,表示开启一个会话、启动进程,并跟踪后续交互信息
spawn passwd root
3.4send (发送)
向进程发送字符串,用于模拟用户的输入
该命令不能自动回车换行,一般要加 \r 或者 \n ,表示换行。
expect "密码" {send "abc123\r"}
或
expect "密码"
send "abc123\r"
#同一行send部分要有{} 换行send部分不需要有{}
expect
"密码1"{ send "abc123\r"}
"密码2"{ send "123456\r"}
"密码3"{ send "123123\r"}
#expect支持多个分支,只要匹配了其中一个情况,执行相应的send语句后退出该expect语句
3.5结束符
expect eof (等待执行结束)
表示交互结束,等待执行结束,退回到原用户,与spawn对应
比如:切换到root用户,expect脚本默认的是等待10s,当执行完命令后,默认停留10s后,就会自动切回原用户。
interact (执行完成后保持交互状态,把控制权交给控制台)
执行完成后保持交互状态,把控制权交给控制台,会停留在目标终端,这个时候就可以手工操作了,interact 后的命令不起作用
比如 interact 会保持在终端而不会退回到原终端,比如切换到 root 用户,会一直在 root 用户状态下
比如2 ssh 到另一服务器,会一直在目标服务器终端,而不会切回的原服务器
需要注意的是:expect eof 与 interact 只能二选一
3.6set
设置超时时间,过期则继续执行后续指令
默认,timeout是10s
expect 默认的超时时间是10秒,通过 set 命令可以设置会话超时时间,若不限制超时时间则应设置为-1
set timeout 20
3.7exp_continue
exp_continue 附加于某个 expect 判断项之后,可以使该项匹配后,还能继续匹配该 expect 判断语句内的其他项
exp_continue 类似于控制语句中 continue 语句,表示允许 expect 继续向下执行指令
例如,将判断交互输出中是否存在 yes/no 或 *password , 如果匹配 yes/no 则输出 yes 并再次执行判断;如果匹配 *password 则输出 123123 并结束该段 expect 语句,操作如下:
expect {
"(yes/no)" {send "yes\r"; exp_ continue; }
"*password" {set timeout 300; send "abc123\r";}
}
3.8 send_ user
回显命令,相当于echo
3.9 接收参数
expect 脚本可以接受从 bash 命令行传递的参数,使用[lindex $argv n] 获得。
其中 n 从0开始,分别表示第一个, 第二个,第三个…参数。
set hostname [lindex $argv 0] #相当于 hostname=$1
set password [lindex $argv 1] #相当于 password=$2
#expect直接执行,需要使用 expect 命令去执行脚本
4.示例
1.无交互登录到远程服务器
[root@yzq mnt]#cat ssh.sh
#!/usr/bin/expect
需要用expect自己的解释器,不要写成bash否则无法识别
spawn ssh root@192.168.28.100
开启一个程序,这个程序是ssh远程登录
expect {
"password"
{ send "123456\r"; }
}
捕获内容,当出现password的时候,就会向程序发送密码
interact
交互,否则会直接退出远程服务器
链接成功
[root@yzq mnt]#./ssh.sh
spawn ssh root@192.168.28.100
root@192.168.28.100's password:
Last login: Fri Aug 12 16:30:48 2022 from 192.168.28.10
2.无交互使得另一台主机的新磁盘挂载
[root@yezq ~]# cat fdisk.sh
#!/bin/bash
expect -c " //在bash环境下调用expect
spawn ssh root@192.168.28.100
expect \"password:\" { send \"123456\r\"}
expect \"]#\" { send \"fdisk /dev/sdb\r\"}
expect \"):\" { send \"n\r\"}
expect \"):\" { send \"p\r\"}
expect \"):\" { send \"\r\"}
expect \"):\" { send \"\r\"}
expect \"):\" { send \"\r\"}
expect \"):\" { send \"w\r\"}
expect \"]#\" { send \"mkdir /data\r\"}
expect \"]#\" { send \"mkfs.xfs /dev/sdb1\r\"}
expect \"]#\" { send \"mount /dev/sdb1 /data\r\"}
expect \"]#\" { send \"df -h\r\"}
expect eof
"
3.创建用户并设置用户密码
[root@yzq mnt]#./usr.sh sb
spawn passwd sb
更改用户 sb 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
[root@yzq mnt]#cat usr.sh
#!/bin/bash
username=$1
useradd $username
/usr/bin/expect <<-EOF
spawn passwd $username
expect {
"新的 密码"
{ send "123456\r";exp_continue }
"重新输入新的 密码"
{ send "123456\r"; }
}
EOF
三、关于变量
引用位置变量,定义位置变量比较麻烦。我们可以结合shell脚本中的方式实行嵌入式模式,将expect过程融入shell当中,方便执行和处理在shell脚本那种调用expect
注意:使用嵌入式时,expect捕捉的内容不要和send发送写在同一行,不然它会判断为都是捕捉的内容
总结
借助 expect 处理交互的命令,可以将交互过程如 ssh 登录,ftp 登录等写在一个脚本上,使之自动化完成。
适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率,使用它,你甚至可以仅仅执行一个脚本来完成分布式应用系统的搭建与维护。