今天继续学习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作用:启动新的产生交互的进程

下面我们以修改一个已存在账户的密码为例,举例如下:

bash 复制代码
[root@localhost ~]# useradd tom
[root@localhost ~]# passwd tom
更改用户 tom 的密码 。
新的密码: 
无效的密码: 密码少于 8 个字符
重新输入新的密码: 
passwd:所有的身份验证令牌已经成功更新

基于expect交互界面做法

bash 复制代码
[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 eof

passwd:所有的身份验证令牌已经成功更新。
expect1.8> exit

其中expect作用:获取从spawn命令执行的命令和程序后产生的交互信息。看看是否匹配,如果匹配,就开始执行expect进程接收字符串。

send命令的主要作用是,在expect命令匹配完指定的字符后,发送指定的字符串给系统程序,在字符中可以支持部分特殊转义符,比如:n(回车)r(换行)t(制表符)等。

下面是上述实验的expect脚本案例:

bash 复制代码
[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进行非交互式的形式查看另一端口信息:

bash 复制代码
[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.145

Authorized 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:

bash 复制代码
[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:

bash 复制代码
[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

以上脚本也能支持更多变量写入

bash 复制代码
[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中使用该命令)

bash 复制代码
#!/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

方法二

bash 复制代码
[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-bracket
    while 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.dg..d。如果想要匹配包含\n字符可以使用 [.\n]
* 匹配前面子表达式0次或者多次,例: goo*dgo.*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\}匹配两位到三位数字
注: egrepawk使用{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

bash 复制代码
[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的功能对其设置脚本实现非交互式批量创建用户及密码
bash 复制代码
[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
do
        expect<<EOF
        spawn passwd $i
        expect {
                "*密码: " { 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:所有的身份验证令牌已经成功更新。
相关推荐
云上小朱8 小时前
文件下载-ubuntu操作系统下载指定文件
linux·shell
hmcjn(小何同学)8 小时前
轻松Linux-9.进程间通信
linux·运维·服务器·c++·bash
上海达策TECHSONIC8 小时前
经验分享:如何让SAP B1数据库性能提升50%
运维·数据库·运维开发
月光在发光8 小时前
19_内核模块挂载问题处理
linux·运维·服务器
Liang_GaRy8 小时前
心路历程-Linux如何赋予权限?
linux·运维·服务器
落羽的落羽8 小时前
【C++】C++11的包装器:function与bind简介
c++·学习
Hello阿尔法8 小时前
基于 NFS 的文件共享实现
linux·嵌入式
打不了嗝 ᥬ᭄8 小时前
【Linux】线程概念与控制
linux·c++