目录
Here Document免交互
Here Document免交互概述
- Here Document免交互使用I/O重定向的方式将命令列表提供给交互式程序或命令(ftp、cat、read等)
- Here Document免交互是标准输入的一种替代品,可以帮助脚本开发人员不必使用临时文件来构建输入信息,直接就地产出一个“文件”并用作“命令”的标准输入。Here Document也可以与非交互式程序和命令一起使用
Here Document语法格式与注意事项
注意事项
- 标记可以使用任意合法字符(通常用EOF)
- 结尾的标记一定要顶格写,前面不能有任何字符
- 结尾的标记后面也不能有任何字符(包括空格)
- 开头标记前后的空格会被省略掉
语法格式及详细注释
- 命令 <<标记
…
内容
…
标记 - 第一个标记为传入内容的开始,第二个标记为传入内容的结束
基本格式
[root@localhost mail]# cat > 10.txt <<EOF
> QWE123
> qwe321
> qweqwe
> EOF
[root@localhost mail]# cat 10.txt
QWE123
qwe321
qweqwe
免交互方式实现对行数的统计
[root@localhost mail]# wc -l <<EOF
> 456
> 789
> 123
> 444
> EOF
4
【将要统计的内容置于标记"EOF"之间,直接将内容传给wc -l进行统计】
将免交互输入的内容通过read命令打印出来
[root@localhost mail]# read i << EOF
【开头的EOF前后可以有空行,会被自动省略,但结尾的EOF不能有空行】
> take
> easy
> EOF
[root@localhost mail]# echo $i
take
【read只能接受一行变量】
使用免交互方式通过passwd给用户设置密码
[root@localhost mail]# passwd qz <<QQQ
【标记可以使用任意合法字符(通常为EOF),但前后标记使用的字符需一致】
> 111222
> 111222 【两行一样的代表输入的新密码和确认密码】
> QQQ
更改用户 qz 的密码 。
新的 密码:无效的密码: 密码少于 8 个字符
重新输入新的 密码:passwd:所有的身份验证令牌已经成功更新。
通过免交互方式实现变量的替换
[root@localhost /]# cat EOF1.txt
I am going go
[root@localhost /]# vim 1.sh
#!/bin/bash
file="EOF1.txt" 【中间有符号时最好用引号引起来】
i=go
cat > $file <<EOF
I am going to $i
EOF
cat EOF1.txt
通过免交互实现整体赋值给变量
[root@localhost /]# ./1.sh
This is Line 1
You are very good!
yes! I am going to home!
[root@localhost /]# vim 1.sh
#!/bin/bash
qz="yes! I am going to home!"
qz1=$(cat <<EOF 【qz1=$(cat <<'EOF' 对标记加单引号,即可关闭变量替换】
This is Line 1
You are very good!
$qz
EOF
)
echo "$qz1" 【这里给变量加上引号即可换行输出】
通过免交互去除每行之前的TAB字符
[root@localhost /]# ./1.sh
This is Line 1
You are very good!
yes! I am going to home!
[root@localhost /]# vim 1.sh#!/bin/bash
qz="yes! I am going to home!"
qz1=$(cat <<-EOF 【在标记前加"-"即可抑制各行首的TAB键的输出但不能抑制空格】
This is Line 1
You are very good!
$qz
EOF
)
echo "$qz1"
通过免交互实现多行注释
- Bash的默认注释是"#",该注释方法只支持单行注释;Hero Document 的引入解决了多行注释的问题
- ":"代表一个不执行任何操作的空命令,所以中间标记区域的内容不会被执行,会被bash忽略掉,因此即可达到批量注释的效果
[root@localhost /]# ./1.sh
yes! I am going to home!
[root@localhost /]# vim 1.sh#!/bin/bash
qz="yes! I am going to home!"
:<<EOF
This is Line 1
You are very good!
$qz
EOFecho "$qz"
Expect概述
- expect工具是建立在tcl语言基础之上的
- expect是一个免费的编程工具,用来实现自动的交互式任务,而无需人为干预。说白了,expect就是一套用来实现自动交互功能的软件工具
- 在实际工作中,我们运行命令、脚本或程序时,这些命令、脚本或程序都需要从终端输入某些继续运行的指令,而这些输入都需要人为的手工进行。而利用expect,则可以根据程序的提示,模拟标准输入提供给程序,从而实现自动化交互执行。这就是expect
Expect基本命令
1.脚本解释器
- expect脚本中首先引入文件,表明具体使用的是某一个shell
- #!/usr/bin/expect
2.spawn
- spawn后面通常跟一个linux执行命令,表示开启一个会话、启动进程,并跟踪后续交互信息
- 例如:spawn passwd qz
3.expect
- 用于接收命令执行后的输出,然后与期望的字符串匹配
- 判断上次输出结果中是否包含指定的字符串,如果有则立即返回,否则就等待超时时间后返回
- 只能捕捉由spawn启动的进程的输出
4.send
- 向进程发送字符串,用于模拟用户的输入;该命令不能自动回车执行,需要加\r(回车)或者\n
- 方式一
- expect “密码” {send “abc123\r”} 【同一行时,send部分要有{ }】
- 方式二
- expect “密码”
- send “$abc123\r” 【不在同一行,换行时,send部分不需要有{ }】
- 方式三
- expect支持多个分支
- 【只要满足其中一个条件,执行相应的send语句后则退出该expect语句】
expect
{
“密码1” {send “111222\r”}
“密码2” {send “222333\r”}
“密码3” {send “333444\r”}
}
5.结束符
- expect EOF
表示交互结束,等待执行结束,退回到原用户,与spawn对应
例如切换到root用户,expect脚本默认的是等待10s。当执行完命令后,默认停留10s后,自动切回了原用户 - interact
执行完成后保持交互状态,把控制权交给控制台,会停留在目标终端而不会退回到原终端,这个时候即可手工操作了,interact后的命令不起作用,比如interact后添加exit,并不会退出root用户。但是如果没有intetact则登录完成后会退出,而不是留在远程终端上
使用interact会保持在终端而不会退回到原终端。例如切换到root用户时,则会一直在root用户状态下;通过ssh链接到另一台服务器时,会一直在目标服务器终端,而不会切回到原服务器
*结束符expect EOF和interact只能二选一
6.set
- expect默认的超时时间为10秒,通过set命令可以设置会话超时时间。当设为-1时,则代表不限制超时时间
set timeout 60
7.exp_continue
- exp_continue附加于某个expect判断之后,可以使该项被匹配后,还能匹配该expect判断语句内的其他项
exp_continue类似于控制语句中的continue语句。表示允许expect继续向下执行指令 - 例如:判断交互输出中是否存在yes/no或*assword。如果匹配yes/no则输出yes并再次执行判断
如果匹配*password则输出abc123并结束该段expect语句
- 注意事项:当使用exp_continue时,如果跟踪的是passwd这样的输入密码后就结束进程的命令,expect{ }外不用再加上expect EOF。因为spawn进程结束后会默认向expect发送EOF,所以再手动加上则会导致后面的expect EOF执行报错
8.send_user
- send_user表示回显命令,类似于echo
9.接收参数
- expect脚本可以接受从bash命令传递的参数,使用[lindex $argv n]获得。其中n从0开始,分别表示第一个,第二个…参数
- 例如
set hostname [lindex $argv 0] 【相当于hosename=$1的意思】
set password [lindex $argv 1] 【相当于password=$2的意思
使用expect实现su切换用户
- expect直接执行,需要使用expect命令去执行脚本
[root@localhost /]# exit
exit
[qz@localhost /]$ ./expect.sh root 5514
spawn su root
密码:
[root@localhost /]# su ok
[root@localhost /]# vim expect.sh#!/usr/bin/expect
set timeout 60 【设置超时时间】
set username [lindex $argv 0] 【传入参数,argv代表参数列表】
set password [lindex $argv 1]spawn su $username 【开始追踪命令】
expect "密码:" 【免交互执行,捕捉信息并匹配。这里使用的是中文“:”】
send "$password\r"expect "*]#" 【这列的“*]#”相当于“[root@localhost /]#”】
send_user "su ok"interact 【把控制权交给控制台】
#expect EOF 【2个结束符都可,但不能同时执行】
使用expect实现创建用户并设置密码
- 嵌入执行模式,将expect过程融入Shell中,方便执行和处理
[root@localhost /]# ./expect-1.sh qz1 5514
spawn passwd qz1
更改用户 qz1 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
[root@localhost /]# su qz
[qz@localhost /]$ su qz1
密码:
[qz1@localhost /]$
[qz1@localhost /]$ vim expect-1.sh#!/bin/bash
user=$1
password=$2 【非交互的命令放在expect外面】useradd $user
/usr/bin/expect <<EOF 【开始免交互执行】
spawn passwd $user 【开启一个进程跟踪passwd命令,expect只能捕获该进程信息】expect "新"
send "${password}\r"
expect "重"
send "${password}\r"
expect EOF
EOF
使用expect实现ssh自动登录
[root@localhost ~]# ./expect-2.sh 192.168.131.10 5514
spawn ssh 192.168.131.10
root@192.168.131.10's password:
Last login: Fri Mar 19 11:59:10 2021 from 192.168.131.9
[root@localhost ~]# [root@localhost ~]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.131.9 netmask 255.255.255.0 broadcast 192.168.131.255
inet6 fe80::3c3b:eafc:aeef:6a67 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:e3:f1:cd txqueuelen 1000 (Ethernet)
RX packets 13468 bytes 1176230 (1.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 6055 bytes 776947 (758.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0[root@localhost ~]# vim expect-2.sh
#!/usr/bin/expect
set timeout 10
set host [lindex $argv 0]
set passwd [lindex $argv 1]spawn ssh $host
expect {
"Connection refused" exit 【连接失败的情况,比如对方ssh服务关闭】
"Name or service not know" exit 【找不到服务器,比如输入的IP地址不正确】
"(yes/no)" {send "yse\r"; exp_continue}
"*password:" {send "${passwd}\r"}
}#interact
expect EOF 【以expect为结束符。则执行完命令后会自动切回原用户】
- 以interact为结束符,会一直在目标服务器终端,而不会切回到原服务器。
[root@localhost ~]# ./expect-2.sh 192.168.131.10 5514
spawn ssh 192.168.131.10
root@192.168.131.10's password:
Last login: Fri Mar 19 11:57:34 2021 from 192.168.131.9
[root@localhost ~]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.131.10 netmask 255.255.255.0 broadcast 192.168.131.255
inet6 fe80::f8fc:7087:375:efee prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:14:03:40 txqueuelen 1000 (Ethernet)
RX packets 1272 bytes 147039 (143.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 502 bytes 79602 (77.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@localhost ~]# vim expect-2.sh#!/usr/bin/expect
set timeout 10
set host [lindex $argv 0]
set passwd [lindex $argv 1]spawn ssh $host
expect {
"Connection refused" exit
"Name or service not know" exit
"(yes/no)" {send "yse\r"; exp_continue}
"*password:" {send "${passwd}\r"}
}interact
#expect EOF