shell编程之免交互–Here Document与Expect
一、Here Document免交互
1.1Here Document概述
- 使用I/O重定向的方式将命令列表供给交互式程序
- 标准输入执行方式
- 语法格式
命令 <<标记 EOF
……
……
标记EOF
1.2Here Document使用注意事项
- 标记可以是任意大写字符,一般用EOF
- 结尾的标记要顶格写,前面不能有任何字符
- 结尾的标记后面也不能有任何字符,包括空格
- 开头标记前后的空格会被省略掉
1.3 Here Document常规用法
1.3.1通过read命令接收并打印
[root@localhost ~]# read i <<EOF > hello world > my name is lisi > EOF > [root@localhost ~]# echo $i > hello world
只能将单行内容重定向到标记前的变量
1.4通过passwd给用户设置密码
示例
#!/bin/bash
passwd liu <<EOF
this is password
this is password
EOF
~
[root@localhost ~]# sh test23.txt liu Abc123
更改用户 liu 的密码 。
新的 密码:重新输入新的 密码:passwd:所有的身份验证令牌已经成功更新。
1.5变量替换
示例
#!/bin/bash
filename="test.txt"
location="kgc"
cat > ${filename} <<EOF
this is ${location} .com
EOF
[root@localhost ~]# vim test24.sh
[root@localhost ~]# sh test24.sh
[root@localhost ~]# ls
99.sh sum.sh test23.txt 模板 下载
anaconda-ks.cfg test01.sh test24.sh 视频 音乐
initial-setup-ks.cfg test11.sh test.txt 图片 桌面
sum50.sh test22.sh 公共 文档
[root@localhost ~]# cat test.txt
this is kgc .com
1.6 变量替换关闭功能
用单引号将重定号后面的标记括起来,就能关闭变量替换功能
[root@localhost ~]# num1=100 [root@localhost ~]# num2=200 [root@localhost ~]# echo $num1 100 [root@localhost ~]# echo $num2 200 [root@localhost ~]# num2=$(cat <<EOF > 300 > $num1 > EOF > ) > [root@localhost ~]# echo $num2 > 300 100 > [root@localhost ~]# echo $num1 > 100 > [root@localhost ~]# num2=$(cat <<'EOF' > 400 > $num1 > EOF > ) > [root@localhost ~]# echo $num2 > 400 $num1
1.7去除每行之前的TAB字符
在<<-EOF 标记前添加- 起抑制制表符的作用
示例
#!/bin/bash
echo "hello"
echo "world"
cat <<EOF
this is ${location} .com
EOF
[root@localhost ~]# sh test24.sh
hello
world
this is .com
#!/bin/bash
echo "hello"
echo "world"
cat <<-'EOF'
this is $location .com
EOF
[root@localhost ~]# sh test24.sh
hello
world
this is $location .com
对比总结
1-可以抑制制表符,但不能抑制空格
2用单引号将标记括起来,可以禁用引用变量
二、expect免交互
2.1Expect概述
Expect是建立在tcl基础上的一个工具,Expect是用来进行自动化控制和测试的工具。主要解决shell脚本中不可交互的问题,对于大规模的linux运维很有帮助
在Linux运维和开发中,我们经常需要远程登录服务器进行操作,在登录的过程是一个交互的过程,可能会需要输入yes/no password等信息。
为了模拟这种输入,可以使用Expect脚本
2.2Expect基本命令
系统一般不自带,需要自己安装
yum install expect -y
2.2.1Expect命令流程
- #!/user/bin/expect 调用expect命令
- spawn:启动进程,并跟踪后续交互信息
- send:向进程发送字符串,用于模拟用户的输入
该命令不能自动回车换行,一般要加、r(回车) - expect
expect的一个内部命令,判断上次输出结果里是否包含指定的字符串,如果有则立即返回,否则就等待超时时间后返回
只能捕捉有spawn启动的进程的输出 - interact:执行完成后保持交互状态,把控制权交给控制台
3.2.2基本命令(expect内容命令)
-
Timeout:指定超时时间,过期则继续执行后续指令
单位是:秒
timeout -1为永不超时
默认情况下,timeout是10秒
-
exp_continue
允许expect继续向下执行指令
-
send_user
回显命令,相当于echo
3.2.3基本命令(expect其他命令)
$argv参数数组
Expect脚本可以接受从bash传递的参数,可以使用[lindex $argc n]获得,n从0开始,分别表示第一个,第二个,第三个…参数
arg:参数
Expect脚本的结尾
expect脚本必须以interact或expect eof结束,执行自动化任务通常expect eof就够了
expect eof是在等待结束标志。由spawn启动的命令在结束时会产生一个eof标记,expect eof就是在等待这个标记
3.3Expect执行方式
3.3.1Expect语法
单一分支语法
expect "password:" {send "mypassword\r"}
多分支模式语法第一种
expect "aaa" {send "AAA\r"}
expect "aaa" {send "AAA\r"}
expect "aaa" {send "AAA\r"} '
send命令不具备回车换行功能,所以需要自己添加\r 或 \n’
多分支模式语法第二种
expect {
"aaa" {send "AAA\r"}
"bbb" {send "BBB\r"}
"ccc" {send "CCC\r"}
}
‘只要匹配了aaa 或bbb或ccc中的任何一个,执行相应的send语句后就会退出该expect语句’
expect {
"aaa" {send "AAA\r";exp_continue}
"bbb" {send "BBB\r";exp_continue}
"ccc" {send "CCC\r"}
}
‘exp_continue表示继续后面的匹配,如果匹配了aaa,执行完send语句后还会继续向下匹配bbb’
‘捕捉内容要用双引号引起来’
‘send要写在{}中,输出信息也要用双引号引起来,分号“;”要写在}里面’
3.3.2直接执行
-
其中,$argv 0 代表位置变量$1
$argv 1 代表位置变量$2
-
#!/usr/bin/expect 是Expect二进制文件的路径
示例
以ssh远程登录为例
[root@localhost~]#cat test22.sh
#!/usr/bin/expect 由 /usr/bin/expect 来加载脚本
set timeout 60 设置超时时间为60秒(未匹配到登出时间)
log file test.log
log_user 1
set hostname [lindex $argv 0] '变量定义'
set password [lindex $argc 1]
spawn ssh root @$hostname '启动spawn'
expect { '匹配条件'
"(yes/no)"
{send "yes\r";exp_continue}
"*password"
{send "$password\r"}
}
interact '将权限转交控制台'
3.3.3嵌入执行
[root@localhost~]#cat test11.sh
#!/bin/bash
hostname=$1
password=$2
/usr/bin/expect<<-EOF
spawn ssh root@${hostname}
expect {
"(yes/no)"
{send "yes\r";exp_continue}
"*password"
{send "$password\r"}
}
expect "*]#"
send "exit\r"
expect eof
EOF 'Expect结束标志,EOF前后不能有空格'
执行脚本
[root@localhost ~]# sh test11.sh 14.0.0.8 Abc123
spawn ssh root@14.0.0.8
root@14.0.0.8's password:
Last login: Tue Jul 28 09:20:48 2020 from 14.0.0.10
[root@localhost ~]# exit
登出
Connection to 14.0.0.8 closed.
3.4Expect案例
案例一 创建用户并设置密码
#!/bin/bash
user=$1
password=$2
useradd $user
/usr/bin/expect <<-EOF
spawn passwd ${user}
expect {
"新的 密码*:"
{send "${password}";exp_continue}
"重新输入新的 密码:"
{send "${password}\r";}
}
expect "成功"
send "exit\r"
expect eof
EOF
案例二
ssh登录
#!/bin/bash
hostname=$1
password=$2
#experct嵌入
/usr/bin/expect <<EOF
spawn ssh root@${hostname}
expect {
"connecting (yes/no)"
{send "yes\r";exp_continue}
"*password:"
{send "${password}\r";}
}
expect "*]#"
send "exit\r"
expect eof;
EOF
[root@localhost ~]# sh test21.sh 14.0.0.8 Abc123
spawn ssh root@14.0.0.8
root@14.0.0.8's password:
Last login: Tue Jul 28 11:15:43 2020 from 14.0.0.8
[root@localhost ~]# exit
登出
Connection to 14.0.0.8 closed.
ect {
“connecting (yes/no)”
{send “yes\r”;exp_continue}
“password:"
{send “${password}\r”;}
}
expect "]#”
send “exit\r”
expect eof;
EOF
[root@localhost ~]# sh test21.sh 14.0.0.8 Abc123
spawn ssh root@14.0.0.8
root@14.0.0.8’s password:
Last login: Tue Jul 28 11:15:43 2020 from 14.0.0.8
[root@localhost ~]# exit
登出
Connection to 14.0.0.8 closed.