文章目录
- [Here Document免交互和Expect自动化交互](#Here Document免交互和Expect自动化交互)
-
- [一、Here Document---免交互](#一、Here Document—免交互)
- 二、Expect自动化交互
-
- 1、expect基本使用
-
- [1.1 脚本解释器](#1.1 脚本解释器)
- [1.2 spawn](#1.2 spawn)
- [1.3 expect](#1.3 expect)
- [1.4 send](#1.4 send)
- [1.5 结束符](#1.5 结束符)
- [1.6 set](#1.6 set)
- [1.7 exp_continue](#1.7 exp_continue)
- [1.8 send_ user](#1.8 send_ user)
- [1.9 接收参数](#1.9 接收参数)
- 2、expect执行脚本
-
- [2.1 su切换用户](#2.1 su切换用户)
- [2.2 免交互修改用户密码](#2.2 免交互修改用户密码)
- [2.3 远程ssh脚本](#2.3 远程ssh脚本)
- [2.4 磁盘分区并格式化](#2.4 磁盘分区并格式化)
- [2.5 免交互远程创建用户](#2.5 免交互远程创建用户)
Here Document免交互和Expect自动化交互
一、Here Document---免交互
1、Here Document 免交互概述
- 使用I/0重定向的方式将命令列表提供给交互式程序或命令,比如ftp、cat或read命令
- 是标准输入的一种替代品可以帮助脚本开发人员不必使用临时文件来构建输入信息,而是直接就地生产出一个"文件"并用作"命令"的标准输入
- Here Document 也可以与非交互式程序和命令一起使用
2、语法格式
bash
命令 <<标记
...
内容 # 标记之间是传入内容
... 标记
注意事项
- 标记可以使用任意合法字符(通常为EOF)
- 结尾的标记一定要顶格写, 前而不能有任何字符
- 结尾的标记后面也不能有任何字符( 包括空格)
- 开头标记前后的空格会被省略掉
3、免交互的用法
3.1 cat命令
bash
[root@localhost ~]#cat <<EOF
> hello
> nihao
> EOF
hello
nihao
#覆盖
[root@localhost ~]#cat > txt << EOF
> xxxx
> 1213
> 0258
> EOF
[root@localhost ~]#cat txt
xxxx
1213
0258
#追加
[root@localhost ~]#cat >>txt<<EOF
> 4561
> 4789
> EOF
[root@localhost ~]#cat txt
xxxx
1213
0258
4561
4789
3.2 tee命令
常用选项 | 说明 |
---|---|
-a | 内容追加到给定的文件而非覆盖 |
-i | 忽略中断信号 |
bash
[root@localhost ~]#tee<<EOF
> 147
> 258
> EOF
147
258
##tee可以直接生成文件,但cat需要">"导出
3.3 wc命令
- 使用 wc -l 命令后面直接跟文件名就可以统计文件内有多少行内容,将要统计的内容置于标记"EOF" 之间,直接将内容传给 wc -l 来统计
bash
#统计行数
[root@localhost ~]#wc -l<<eof
> 159
> 123
> 456
> 174
> 11
> 28
> 22
> 08
> eof
8
3.4 read命令
- 通常使用 read 命令接收用户的输入值时会有交互过程
bash
[root@localhost ~]#read -p "请输入一个数字" ack
请输入一个数字22
[root@localhost ~]#
[root@localhost ~]#echo $ack
22
3.5 passwd命令
- 使用 passwd命令设置密码。EOF 标记之间的两行是输入的密码和确认密码,两行内容必须保持一致,否则密 码设置不成功
bash
#修改用户密码
[root@localhost ~]#passwd zhangsan<<eof
> xxxx.1128
> xxxx.1128
> eof
更改用户 zhangsan 的密码 。
新的 密码:重新输入新的 密码:passwd:所有的身份验证令牌已经成功更新。
4、Here Document 变量设定
-
Here Document 也支持使用变量,如果标记之间有变量被使用,会先替换变量值。
-
如果想要将一些内容写入文件,除了常规的方法外,也可以使用 Here Document。
-
如果写入 的内容中包含变量,在写入文件时要先将变量替换成实际值,在结合 cat 命令完成写入。
bash
[root@localhost data]#vim qw.sh
#!/bin/bash
a="xx.txt"
#新建一个xx.txt文件夹
b="nihao"
cat>$a<<EOF
#用cat命令完成写入
this is $b
EOF
[root@localhost data]#bash qw.sh
[root@localhost data]#cat xx.txt
this is nihao
二、Expect自动化交互
- 是建立在tcl(tool command language)语言基础上的一个工具,常被用于进行自动化控制和测试,解决shell脚本中交互的相关问题
- 使用expect得先进行 expect包的安装
bash
rpm -q expect
#检查expect是否安装
rpm -q tcl
#检查依赖包tcl是否安装
yum install expect -y
#若是未安装,安装expect
bash
[root@localhost data]#rpm -q expect
expect-5.45-14.el7_1.x86_64
[root@localhost data]#rpm -q tcl
tcl-8.5.13-8.el7.x86_64
#expect和tcl均已安装
1、expect基本使用
1.1 脚本解释器
- expect 脚本中首先引入文件,表明使用的事哪一种shell
bash
[root@localhost data]#which expect
/usr/bin/expect
1.2 spawn
- spawn 后面通常跟一个Linux执行命令,表示开启一个会话、进程,并跟踪后续交互信息
1.3 expect
-
判断上次输出结果中是否包含指定的字符串,如果有则立即返回,否则就等待超时时间后返回;只能捕捉有swpan启动的进程输出。
-
用于接受命令执行后的输出,然后和期望的字符串匹配
1.4 send
- 向进程发送字符串,用于模拟用户的输入:该命令不能自动回车换行,一般要加 \r (回车) 或者\ n
bash
1、方式一:
expect "密码" {send "abc123\r"}
#同一行send部分要有{}
2、方式二:
expect "密码"
send "abc123\r"
#换行send部分不需要有{}
3、方式三:
expect 支持多个分支
expect {
#只要匹配了其中一个情况,执行相应的send 语句后退出该expect 语句
"密码1" {send "abc123\r"}
"密码2" {send "123123\r"}
"密码3" {send "123456\r"}
}
1.5 结束符
bash
expect eof
-
表示交互结束,等待执行结束,退回到原用户,与spawn对应
-
比如切换到root用户,expect 脚本默认的等待时间是10s,当执行完命令后,默认停留10s后,自动切回原用户
bash
interact
- 执行完成后保持交互状态,把控制权交给控制台,会停留在目标终端而不会退回到原终端,这个时候就可以手工操作了,interact后的命令不起作用; 比如interact后添加exit,并不会退出root用户。而如果没有interact则登录完成后会退出,而不是留在远程终端上。
- 使用interact会保持在终端而不会退回到原终端; 比如切换到root用户,会一直在root用户状态下:比如ssh到另一服务器,会一直在目标服务器终端,而不会切回的原服务器
注意:expect eof 与 interact 只能二选一
1.6 set
- expect 默认的超时时间是10秒,通过set 命令可以设置会话超时时间,若不限制超时时间则应设置为-1
1.7 exp_continue
- exp_continue附加于某个expect 判断选项之后,可以是该项被匹配后还能继续匹配expect 判断语句内的其他项。
- exp_continue类似于控制语句的continue语句。表示允许expect继续向下执行命令。
注意:使用exp_ continue时,如果跟踪像passwd 这样的输入密码后就结束进程的命令,expect{}外不要 再加上expect eof,因为spawn进程结束后会默认向expect发送eof,,会导致后面的expect eof 执行报错
1.8 send_ user
- 表示回显命令与echo相同
1.9 接收参数
- expect 脚本可以接受从bash命令行传递参数,使用 [lindex $argv n]获得。其中你从0开始,分别表示第一个,第二个,第三个...参数
2、expect执行脚本
2.1 su切换用户
bash
[root@localhost ~]#vim xxx
#!/usr/bin/expect
set timeout 1
#设置超时等待时间
set username [lindex $argv 0]
set password [lindex $argv 1]
#参数传入
spawn su $username
#开始追踪命令
expect "密码"
send "$password\n"
#免交互执行,捕捉信息并匹配
expect "*]$"
send_user "$username 切换成功!"
#把控制权交给控制台
interact
#等同于expect eof,结束符
#验证,切换用户
[root@localhost ~]#chmod +x xxx
[root@localhost ~]#./xxx zhangsan
spawn su zhangsan
[zhangsan@localhost root]$
[zhangsan@localhost root]$ zhangsan 切换成功!
[zhangsan@localhost root]$
2.2 免交互修改用户密码
bash
[root@localhost data]#vim ww
#!/usr/bin/expect
set timeout 2
#设置超时时间为2秒,默认情况是10秒
spawn passwd zhangsan
#spawn追踪后面指令产生的交互过程
expect "新的密码"
send "123123\r"
expect "重新输入新的密码"
send "123123\r"
#send 相当于echo,传送在该交互过程中你的预设值
expect eof
#结束符
#验证,用户生成新的密码
[root@localhost data]#expect ww
spawn passwd zhangsan
更改用户 zhangsan 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
2.3 远程ssh脚本
bash
[root@localhost ~]#vim qaz
#!/usr/bin/expect
set timeout 2
#超时等待时间2秒
set hostname [lindex $argv 0]
set password [lindex $argv 1]
#参数传入
spawn ssh root@$hostname
#开始追踪命令
expect {
"No route to host" exit
#无法匹配时,直接退出
"Connection refused" exit
#同上
"(yes/no)" {send "yes\r";exp_continue}
"*password" {send "$password\r"}
}
interact
#验证,ssh远程登录
[root@localhost ~]#./qaz 192.168.10.12 123
spawn ssh root@192.168.10.12
root@192.168.10.12's password:
Last login: Thu Feb 1 16:24:59 2024 from 192.168.10.11
[root@liuyanfen12 ~]#
2.4 磁盘分区并格式化
bash
[root@localhost ~]#vim cpfq
#!/usr/bin/expect
set timeout 2
set name [lindex $argv 0]
spawn fdisk $name
expect "获取帮助"
send "n\r"
expect "Select"
send "p\r"
expect "分区号"
send "\r"
expect "起始"
send "\r"
expect "Last"
send "+10G\r"
expect "命令"
send "w\r"
interact
[root@localhost ~]#chmod +x cpfq
#添加权限
#验证
[root@localhost ~]#./cpfq /dev/sdb
spawn fdisk /dev/sdb
欢迎使用 fdisk (util-linux 2.23.2)。
更改将停留在内存中,直到您决定将更改写入磁盘。
使用写入命令前请三思。
Device does not contain a recognized partition table
使用磁盘标识符 0xae6c7104 创建新的 DOS 磁盘标签。
命令(输入 m 获取帮助):n
Partition type:
p primary (0 primary, 0 extended, 4 free)
e extended
Select (default p): p
分区号 (1-4,默认 1):
起始 扇区 (2048-41943039,默认为 2048):
将使用默认值 2048
Last 扇区, +扇区 or +size{K,M,G} (2048-41943039,默认为 41943039):+10G
分区 1 已设置为 Linux 类型,大小设为 10 GiB
命令(输入 m 获取帮助):w
The partition table has been altered!
Calling ioctl() to re-read partition table.
正在同步磁盘。
#查看磁盘分区情况(/dev/sdb磁盘有一个10G的分区)
[root@localhost ~]#lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 60G 0 disk
├─sda1 8:1 0 5G 0 part /boot
└─sda2 8:2 0 54G 0 part
├─centos-root 253:0 0 50G 0 lvm /
└─centos-swap 253:1 0 4G 0 lvm [SWAP]
sdb 8:16 0 20G 0 disk
└─sdb1 8:17 0 10G 0 part
sr0 11:0 1 4.2G 0 rom /run/media/root/CentOS 7 x86_64
2.5 免交互远程创建用户
bash
[root@localhost ~]#vim cjyh
#!/bin/bash
net=192.168.10
password=123
iplist="
12
13
"
for i in $iplist
do
ip=$net.$i
/usr/bin/expect <<EOF
spawn ssh root@$ip
expect {
"(yes/no)"
{send "yes\r";exp_continue}
"*password"
{send "$password\r"}
}
expect "*]#" {send "useradd xxxx\n"}
expect "*]#" {send "echo 123 |passwd xxxx --stdin\r"}
expect "*]#" {send "exit\r"}
expect eof
EOF
done
#验证
[root@localhost ~]#chmod +x cjyh
[root@localhost ~]#./cjyh
spawn ssh root@192.168.10.12
root@192.168.10.12's password:
Last login: Thu Feb 1 16:49:54 2024 from 192.168.10.11
[root@liuyanfen12 ~]#useradd xxxx
useradd:用户"xxxx"已存在
[root@liuyanfen12 ~]#echo 123 |passwd xxxx --stdin
更改用户 xxxx 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@liuyanfen12 ~]#exit
登出
Connection to 192.168.10.12 closed.
spawn ssh root@192.168.10.13
The authenticity of host '192.168.10.13 (192.168.10.13)' can't be established.
ECDSA key fingerprint is SHA256:XPwaZaTw5yiaSjstVL7RUvtAWazK6knPFGtnu7JUGQ8.
ECDSA key fingerprint is MD5:86:59:fb:79:57:89:ae:83:ef:83:95:66:b0:76:b4:5d.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.10.13' (ECDSA) to the list of known hosts.
root@192.168.10.13's password:
Last login: Wed Jan 17 21:01:17 2024 from 192.168.10.1
[root@liuyanfen13 ~]#useradd xxxx
[root@liuyanfen13 ~]#echo 123 |passwd xxxx --stdin
更改用户 xxxx 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@liuyanfen13 ~]#exit
登出
Connection to 192.168.10.13 closed.