一、Here Document免交互
1. 概念
- 使用I/O重定向的方式将命令列表提供给交互式程序或命令,比如 ftp、cat或read 命令。
- 是标准输入的一种替代品可以帮助脚本开发人员不必使用临时文件来构建输入信息,而是直接就地生产出一个"文件"并用作"命令"的标准输入。Here Document也可以与非交互式程序和命令一起使用。
格式:
命令 <<标记 #标记一般用EOF表示 也可使用其他字符串 但要上下一致
...
内容 #标记直接是传入内容
...
标记
- 结尾的标记一定要顶格写,前面不能有任何字符 ,不然不会被识别成标记
- 结尾的标记后面也不能有任何字符(包括空格)
- 开头标记前后的空格会被省略掉
2. 示例
1. 使用cat命令 免交互 创建并写入文件内容
cat >3.txt <<EOF
> qwe
> asd
> zxc
> 123
> EOF
2. 使用wc -l 免交互统计行数
wc -l <<EOF
>Line1
>Line2
>EOF
3. 使用read命令接收输入的信息并打印出来
read i <<EOF
>Line1
>EOF
echo $i
因为read命令的特性 只能接收第一行输入的内容 如果分成多行写入 也只会接收第一行
4. 使用passwd命令 实现免交互设置密码
passwd stu1 <<EOF
> 000000
> 000000
> EOF 这也是较为实用基础的一个秒交互方式
5. 变量替换
#!/bin/bash
file="4.txt"
i="linux"
cat > $file <<EOF
I love $i
EOF
会先将变量替换成实际值,再结合cat 命令完成写入
实际执行结果和第一个举例相同 但这里演示的是用变量替换传入
6. 整体赋值给变量
#!/bin/bash
i="linux"
newi=$(cat <<EOF #将cat的免交互查看内容整体赋值给一个新变量 通过echo打印
I love $i
EOF
)
echo $newi
~
上述情况 如若想取消变量替换功能 在EOF加 ‘’ 即可
例如:
#!/bin/bash
i="linux"
newi=$(cat <<'EOF'
I love $i
EOF
)
echo $newi
~
将会输出原字符
7. 抑制每行之前的TAB制表符
#!/bin/bash
i="linux"
newi=$(cat <<-EOF #在EOF前加 - 即可
I love $i
EOF
)
echo $newi
8. 多行注释
- Bash 的默认注释是“#”,该注释方法只支持单行注释:Here Document 的引入解决了多行注释的问题。
- ":"代表什么都不做的空命令。中间标记区域的内容不会被执行,会被bash忽略掉,因此可达到批量注释的效果。
#!/bin/bash
i="linux"
: <<EOF #标记内的字符串都不会生效
I love $i
EOF
echo "000000"
~
~
二、Expect
- expect建立在tcl语言基础上的一个工具,常被用于进行自动化控制和测试,解决shell脚本中交互相关的问题。(一般都是未安装的 需要安装)
1. 基本命令
1.1 脚本解释器
#!/usr/bin/expect
#expect脚本中首先引入文件,表明使用的是哪一个shell
1.2 spawn命令
spawn后面通常跟一个Linux执行命令,表示开启一个会话、启动进程,并追踪后续交互信息。
例如:
spawn passwd wang
1.3 expect
- 判断上次输入结果中是否包含指定的字符串,如果有则立即返回,否则就等待超时时间后返回:只能捕捉由spawn启动的进程的输出;
用于接收命令执行后的输出,然后和期望的字符串匹配
1.4 send
- 向进程发送字符串,用于模拟用户的输入;该命令不能自动回车换行。一般要加\r(回车)或者\n(换行符)
例如:
第一种:
expect"密码”{ send "abc123/r"}
#同一行send部分要有{}
#expect捕捉 “密码二字” 如果符合就send模拟输出并换行
第二种:
expect “密码”
send “$abc123\r” #换行send部分不需要有{}
第三种:
expect “支持多个分支
expect { #只要匹配了其中一个情况,执行相应的send语句后退出该expect语句
"密码1 {
send "abc123\r"}"
"密码2 {
send "123123\r"}"
"密码3 {
send "123123\r"}"
}
1.5 结束符 expect eof / interact
expect eof
- 表示交互结束,等待执行结束,退回到原用户,与spawn对应
- 比如切换到root用户,expect脚本默认的是等待10s,当执行完命令后,默认停留10s后,自动切回了原用户
interact
- 执行完成后保持交互状态,把控制权交给控制台,会停留在目标终端,这个时候就可以手工操作了,interact后的命令不起作用,
- 比如interact会保持在终端而不会退回到原终端,比如切换到root用户,会一直在root用户状态下;比如ssh到另一服务器,会一直在目标服务器终端,而不会切回的原服务器。
但两种结束符只能同时使用一个
1.6 set
- expect 默认的超时时间是10秒,通过set命令可以设置会话超时时间,若不限制超时时间则应设置为-1.
例:
set timeout 30
set timeout -1 #为永不超时
1.7 exp_continue
- exp_continue 附加于某个expect判断项之后,可以使该项匹配后,还能继续匹配该expect判断语句内的其他项。exp_continue类似于控制语句中continue语句。表示允许expect继续向下执行指令
例如:
expect
"(yes/no)" {
send "yes\r"; exp_ continue; }
"password" {
set timeout -1; send "abc123\r";}
# 加了exp_ continue 可以理解为并行执行 无论第一条是否判断成立 都会继续匹配下一项
但是此例子expect{
}外不要加expect eof结束符
因为spawn进程结束后会默认向expect发送eof,,会导致后面的expect eof 执行报错
1.8 send_ user
- 相当于echo
1.9 接收参数
- expect脚本可以接受从bash命令行传递的参数,使用[lindex $argv n] 获得。类似于位置参数
- 其中n从0开始,分别表示第一一个, 第二个,第三个…参数。
例如:
set hostname [lindex $argv 0]
相当于hostname=$1
set password [lindex $argv 1]
相当于password=$2
2. 示例
1. 参数传入
切换root用户的免交互
#!/bin/expect
set username [lindex $argv 0]
set password [lindex $argv 1]
#开始追踪命令
spawn su $username
#免交互执行,捕捉信息并匹配
expect "密码"
send "$password\r"
expect "*]#"
#把控制权交给控制台
interact
#expect eof
2. 嵌入执行模式,将expect 过程融入Shell 当中
创建用户 并设置密码
#!/bin/bash
user=$1
passwd=$2
useradd $user
#非交互命令放在外面
/usr/bin/expect <<EOF
开始执行免交互
spawn passwd $user #追踪命令交互过程
expect "新的*" #捕捉信息
send "$passwd\r" #模拟输入
expect "重新*"
send "$passwd\r"
expect eof #创建用户的交互 直接expect eof即可
EOF
3. shell自动登陆
#!/usr/bin/expect
set timeout 5
set hostname [lindex $argv 0]
set password [lindex $argv 1]
spawn ssh $hostname
expect {
"Connection refused" exit
"Name or service not known" exit
"to continue" {
send "yes\r";exp_continue}
"password:" {
send "$password\r"}
}
interact