今天继续学习shell脚本
ssh服务
通过ssh服务进行远程连接
格式为:服务类型 用户名@要连接的IP地址 例如:ssh root@192.168.60.145
宿主机和虚拟机之间的通信原理,互联采用的虚拟网卡进行互联,注意看那个虚拟网卡要先看虚拟机设置是网卡信息。
互联步骤(宿主机与虚拟机):利用win+r打开命令提示符,在进行ssh root@192.168.60.145(虚拟机IP) , yes,进行互联,所产生的ssh有关信息就放在了c盘用户下的sh文件夹的knowns-hostname中
虚拟机之间互联也是采用该命令。
一.Shell中的expect
expect 将交互式的操作,利用脚本的形式,转为非交互是的操作。(本质上就是将交互式的内容逐一写入脚本中,使其实现通过脚本就能自动运行)
expect 的安装
yum install -y expect
如何使用expect
通过上面expect的工作流程,我们可以认识到,expect的内置命令:spawn(启动交互进程)、expect(获取关键字)、send(发送响应内容)等非常重要,所以下面我们先来了解下它们的使用。
spawn:由它进行代替交互
expect: 在交互时所产生的步骤关键点
send:发送在交互的时候所输入的内容
spawn命令
spawn作用:启动新的产生交互的进程
下面我们以修改一个已存在账户的密码为例,举例如下:
[root@localhost ~]# useradd tom
[root@localhost ~]# passwd tom
更改用户 tom 的密码 。
新的密码:
无效的密码: 密码少于 8 个字符
重新输入新的密码:
passwd:所有的身份验证令牌已经成功更新
基于expect交互界面做法
[root@localhost ~]# expect
expect1.2> spawn passwd tom
spawn passwd tom
11145
expect1.3> expect "密码: "
更改用户 tom 的密码 。
新的密码: expect1.4> send "123456\r"
expect1.5> expect "密码: "无效的密码: 密码少于 8 个字符
重新输入新的密码: expect1.6> send "123456\r"
expect1.7> expect eofpasswd:所有的身份验证令牌已经成功更新。
expect1.8> exit
其中expect作用:获取从spawn命令执行的命令和程序后产生的交互信息。看看是否匹配,如果匹配,就开始执行expect进程接收字符串。
send命令的主要作用是,在expect命令匹配完指定的字符后,发送指定的字符串给系统程序,在字符中可以支持部分特殊转义符,比如:n(回车)r(换行)t(制表符)等。
下面是上述实验的expect脚本案例:
[root@localhost ~]# vim user_pwd.sh
#!/usr/bin/expect
spawn passwd tom
expect {
"新的密码: " { send "123.com\r"; exp_continue }
"新的密码: " { send "123.com\r" }
eof
}
[root@localhost ~]# ./user_pwd.sh
spawn passwd tom
更改用户 tom 的密码 。
新的密码:
无效的密码: 密码少于 8 个字符
重新输入新的密码:
passwd:所有的身份验证令牌已经成功更新。
利用expect进行非交互式的形式查看另一端口信息:
[root@localhost ~]# vim ssh_login.sh
#!/usr/bin/expect
spawn ssh root@192.168.60.145
expect {
"*yes/no* " { send "yes\r"; exp_continue }
"*password: " { send "q1w2e3@123!!!!!\r" }
eof
}
[root@localhost ~]# ./ssh_login.sh
spawn ssh root@192.168.60.145Authorized users only. All activities may be monitored and reported.
root@192.168.60.145's password: [root@localhost ~]#
exp_continue命令
exp_continue命令的主要作用是,如果需要一次匹配多个字符串,那么多次匹配字符串并执行不同的动作中,可以让expect程序实现继续匹配的效果。
send_user命令
send_user命令的作用是:用来打印expect脚本信息,类似shell里的echo命令。
二.expect变量
普通变量
expect中定义普通变量的语法如下:
set为变量名 变量值
puts 进行调取
例如:
set chengshi "beijing"
调取变量的方法是:
puts $变量名
#或者
send_user "$变量名"
expect中位置参数变量
如何向expect脚本中像shell一样传递类似于$0、$1等位置参数,用于接收及控制expect脚本传递位置参数变量呢?
expect是通过如下语法来进行的:
set <变量名称> [lindex $argv <param index> ]
当然,除了基本的位置参数外,expect还支持其它的特殊参数,比如:
$argc 表示传入参数的个数
$argv0 表示当前执行脚本的名称
案例1:
[root@localhost ~]# vim exp_var.sh
#!/usr/bin/expect
set var1 [lindex $argv 0]
puts $var1
[root@localhost ~]# chmod +x exp_var.sh
[root@localhost ~]# ./exp_var.sh 1
1
[root@localhost ~]# ./exp_var.sh 12
12
案例2:
[root@localhost ~]# vim exp_var2.sh
#!/usr/bin/expect
# Filename: expect_var2.exp
set file1 [lindex $argv 0]
set file2 [lindex $argv 1]
set file3 [lindex $argv 2]
puts "The files are : $file1 $file2 $file3"
puts "The number of files are: $argc"
puts "The expect script name is: $argv0"
[root@localhost ~]# chmod +x exp_var2.sh
[root@localhost ~]# ./exp_var2.sh
The files are :
The number of files are: 0
The expect script name is: ./exp_var2.sh
[root@localhost ~]# ./exp_var2.sh 1.txt
The files are : 1.txt
The number of files are: 1
The expect script name is: ./exp_var2.sh
[root@localhost ~]# ./exp_var2.sh 1.txt 2.txt
The files are : 1.txt 2.txt
The number of files are: 2
The expect script name is: ./exp_var2.sh
[root@localhost ~]# ./exp_var2.sh 1.txt 2.txt 3.txt
The files are : 1.txt 2.txt 3.txt
The number of files are: 3
The expect script name is: ./exp_var2.sh
以上脚本也能支持更多变量写入
[root@localhost ~]# vim exp_var.sh
#!/usr/bin/expect
set var1 [ lindex $argv 0 ]
set var2 [ lindex $argv 1 ]
puts "$var1 \t $var2"
[root@localhost ~]# ./exp_var.sh 1 2
1 2
三.expect中的if条件语句(了解)
[root@localhost ~]# vim expect-if.exp
#!/usr/bin/expect
# Filename: expect-if.exp
if {$argc <= 3} {
puts "The IP numbers <= 3"
} else {
puts "The IP numbers > 3"
}
[root@localhost ~]# chmod +x expect-if.sh
[root@localhost ~]# ./expect-if.sh 192.168.200.{1..3}
The IP numbers <= 3
[root@localhost ~]# ./expect-if.sh 192.168.200.{1..5}
The IP numbers > 3
四.expect中的for条件语句(了解)
{ set i 1 } 定义i的值为1
{ $i <= 10 }循环的条件
{ incr i 1} 制定$i的增量值,必须写在这行的末尾处,默认增量值为1
案例:
[root@localhost ~]# cat expect-for.exp
#!/usr/bin/expect
for { set i 1 } { $i <= 10 } { incr i 1 } {
puts "$i"
}
[root@localhost ~]# expect expect-for.exp
1
2
3
4
5
6
7
8
9
10
五.expect中的while条件语句(了解)
案例:
[root@localhost ~]# vim expect-while.exp
#!/usr/bin/expect
set i 1
while {$i <= 10} {
puts "$i"
sleep 1
incr i 1
}
[root@localhost ~]# expect expect-while.exp
1
2
3
4
5
6
7
8
9
10
六.expect中的常用关键字
eof关键字
就是执行开始和结束时候用的
cat >>file <<OEFrr content rr
timeout关键字
设置超时时间
set timeout -1 -- 永久不超时
set timeout 0 -- 立即执行
set timeout XX -- 设定具体的timeout时间(秒),默认是10秒
七.在shell脚本中执行expect命令
用expect -c 就可以在shell中用expect命令
案例:
方法一(脚本声明为shell,用 -c 调用expect命令,利用-c “” 的形式,但这个不能在openeuler中使用该命令)
#!/bin/bash
for i in [ 192.168.47.177 192.168.47.163 ]
do
expect -c "
spawn ssh root@$i ip a
expect {
"*yes/no*" { send "yes\r";exp_continue }
"*password:" { send "q1w2e3@123!!!!!\r";exp_continue }
}
expect eof
"
done
方法二
[root@localhost ~]# vim test.sh
#!/bin/bash
for i in [ 192.168.47.177 192.168.47.163 ]
do
expect <<EOF
spawn ssh root@$i ip a
expect {
"*yes/no*" { send "yes\r";exp_continue }
"*password:" { send "q1w2e3@123!!!!!\r";exp_continue }
}
EOF
done
[root@localhost ~]# chmod +x test.sh
[root@localhost ~]# ./test.sh
missing close-bracketwhile executing
"spawn ssh root@["
spawn ssh root@192.168.60.145 ip a
sed编辑器(对shell脚本的修改)
案例:对cxc脚本中的tom换成join。实现非交互式写入
[root@localhost ~]# sed -i "s/tom/join" cxc.sh
脚本内容改变四剑客:
awk
grep
find
sed
八.正则表达式
元字符 | 含义及用法 |
---|---|
\ | 转义字符,用于取消特殊符号的含义,例: \! 、 \n 、 \$ 等 |
^ | 匹配字符串开始的位置,例:^a 、^the 、^# 、^[a-z] |
$ | 匹配字符串结束的位置,例: word$ 、^$ 匹配空行 |
. | 匹配除\n 之外的任意的一个字符,例: go.d 、g..d 。如果想要匹配包含\n字符可以使用 [.\n] |
* | 匹配前面子表达式0次或者多次,例: goo*d 、 go.*d |
[list] | 匹配list列表中的一个字符,例: go[ola]d ,[abc] 、[a-z] 、[a-z0-9] 、[0-9] 匹配任意一位数字 |
[^list] | 匹配任意非list列表中的一个字符,例:[^0-9] 、[^A-Z0-9] 、[^a-z] 匹配任意一位非小写字母 |
\{n\} | 匹配前面的子表达式n次,例: go\{2\}d 、 [0-9]\{2\} 匹配两位数字 |
\{n,\} | 匹配前面的子表达式不少于n次,例: gol{2,l}d 、[0-9]\{2,\} 匹配两位及两位以上数字 |
\{n,m\} | 匹配前面的子表达式n到m次,例 : go\{2,3\}d 、[0-9]\{2,3\} 匹配两位到三位数字 |
注: egrep 、 awk 使用{n} 、{n,} 、{n,m} 匹配时 {} 前不用加 \ |
以上为shell脚本支持的,支持的工具为:grep、egrep、sed、awk
以下要用-p来用,支持的工具:grep、egrep、sed、awk,注意grep要配合-E或者-P使用
\w | 匹配包括下划线的任何单词字符。 |
\W | 匹配任何非单词字符。等价于[^A-Za-z0-9_] 。 |
\d | 匹配一个数字字符。 |
\D | 匹配一个非数字字符。等价于[^0-9] 。 |
\s | 空白符。 |
\S | 非空白符。 |
grep -E 等价于egrep,都是一样的输出结果
案例:筛选出文本中只用0-9数字信息的
筛选出只有两字符的有关信息,grep -E等价于egrep
[root@localhost ~]# grep '[^0-9]' grep.txt
1561d1as6 da5
56551asd a1
6ad15d1a5da
56156ada5gsggjtjj
asdafasf
aseefsdfsdfsd
[root@localhost ~]# grep '[0-9]' grep.txt
1561d1as6 da5
56551asd a1
6ad15d1a5da
56156ada5gsggjtjj
55665659595913156
565656515
54654
[root@localhost ~]# grep '[0-9]\{4\}' grep.txt
1561d1as6 da5
56551asd a1
56156ada5gsggjtjj
55665659595913156
565656515
54654
[root@localhost ~]# egrep '[0-9]{4}' grep.txt
egrep: warning: egrep is obsolescent; using grep -E
1561d1as6 da5
56551asd a1
56156ada5gsggjtjj
55665659595913156
565656515
54654
今日作业
利用chpasswd的功能对其设置脚本实现非交互式批量创建用户及密码
[root@localhost ~]# vim test.sh
#!/bin/bash
#批量更改用户密码
user=$(cat user_passwd.txt | cut -d ':' -f1)
passwd=$(cat user_passwd.txt | cut -d ':' -f2)for i in $user
doexpect<<EOFspawn passwd $iexpect {"*密码: " { send "$passwd\r"; exp_continue }"*密码: " { send "$passwd\r"; }}
EOF
done
[root@localhost ~]# ./test.sh
spawn passwd user1
更改用户 user1 的密码 。
新的密码:
无效的密码: 密码少于 8 个字符
重新输入新的密码:
passwd:所有的身份验证令牌已经成功更新。
spawn passwd user2
更改用户 user2 的密码 。
新的密码:
无效的密码: 密码少于 8 个字符
重新输入新的密码:
passwd:所有的身份验证令牌已经成功更新。
spawn passwd user3
更改用户 user3 的密码 。
新的密码:
无效的密码: 密码少于 8 个字符
重新输入新的密码:
passwd:所有的身份验证令牌已经成功更新。
spawn passwd user4
更改用户 user4 的密码 。
新的密码:
无效的密码: 密码少于 8 个字符
重新输入新的密码:
passwd:所有的身份验证令牌已经成功更新。
spawn passwd user5
更改用户 user5 的密码 。
新的密码:
无效的密码: 密码少于 8 个字符
重新输入新的密码:
passwd:所有的身份验证令牌已经成功更新。