第九章 expect 和grep命令

一、expect介绍

expect 是一个免费的编程工具,用来实现自动的交互式任务,而无需人为干预。说白了, expect
就是一套用来实现自动交互功能的软件。需要安装

yum install -y expect

expect基础
在使用 expect 时,基本上都是和以下四个命令打交道:
命令 作用
spawn 启动新的进程
expect 从进程接收字符串
send 用于向进程发送字符串
interact 允许用户交互
1.spawn 命令用来启动新的进程, spawn 后的 expect 和 send 命令都是和使用 spawn 启动的新进程进行交互。
2.expect 通常用来等待一个进程的反馈,我们根据进程的反馈,再使用 send 命令发送对应的交互
命令。
3.send 命令接收一个字符串参数,并将该参数发送到进程。
4.interact 命令用的其实不是很多,一般情况下使用 spawn 、 expect 和 send 和命令就可以很好的完成我们的任务;但在一些特殊场合下还是需要使用 interact 命令的, interact 命令主要用
于退出自动化,进入人工交互。比如我们使用 spawn 、 send 和 expect 命令完成了ftp登陆主机,执行下载文件任务,但是我们希望在文件下载结束以后,仍然可以停留在ftp命令行状态,以便手
动的执行后续命令,此时使用 interact 命令就可以很好的完成这个任务。

1)expect自动应答的基本步骤

第一步: 运行一个程序或命令=>  spawn 命令信息
第二步: 识别产生信息关键字=>  expect 捕获关键字  {send  应答信息}
第三步: 根据识别关键做处理=>  send  应答信息

二、expect实例

1)自动应答脚本

#!/usr/bin/expect
spawn ssh root@192.168.12.20 uptime
expect "yes/no"
send "yes
"
expect "*assword"
send "1
"
expect eof

2)解释

#1、#!/usr/bin/expect -f:使用expect来解释该脚本
#2、spwan:
spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下-执行是找不到spawn命令的。它主要的功能是给ssh运行进程加个壳,用来传递交互指令;
#3、expect:
expect "*assword":这里的expect也是expect的一个内部命令,这个命令的意思是判断上次输出结果里是否包含“password”的字符串,如果有则立即返回;否则就等待一段时间后返回,这里等待时长就是前面设置的30秒;
#4、send:
send "1
":当匹配到对应的输出结果时,就发送密码到打开的ssh进程,执行交互动作;
首次登陆之后,再次登陆,就不会出现yes/no的提示了,所以上述脚本再次运行会出现spawn 命令出
现交互式提问的expect 匹配不上的情况,此时脚本会阻塞在原地,我们可以set timeout 3设置超时时间,单位为秒,默认情况下是10秒,以保障脚本超时则结束,

#!/usr/bin/expect -f
spawn ssh root@192.168.12.20 uptime
set timeout 3  # 某一条expect语句在原地匹配,超过了3秒,无论是否匹配成功都会继续执行下一条
指令
expect "yes/no"
send "yes
"
expect "*assword"
send "1
"
expect eof

设置超时时间的目的仅仅只是为了让脚本不要一直卡在原地,要真正解决上述问题,需要改写成下述形
式
#!/usr/bin/expect -f
spawn ssh root@192.168.12.20 hostname
# 注意
# 1、{}一定要换行
# 2、下述语句就一个expect,代表匹配了一次,会匹配完一行就匹配下一行
expect {
  "yes/no" {send "yes
";exp_continue}
  "*assword" {send "1
"}
}
expect eof

3)练习

[root@aliyun ~]# cat 1.sh
#!/usr/bin/expect -f
spawn ssh egon@127.0.0.1
set timeout -1  # 设置为-1代表永不超时,如果expect没有捕捉到就一直停在原地
expect {
"yes/no" {send "yes
"}
}
expect {
"password" {send "1
"}
}
expect "*egon*"
send "ls
"
expect "$"
send "pwd
"
expect "$"
send "exit
"  # 注意一定要输入exit结束信号
expect eof  # 最后关闭匹配
[root@aliyun ~]#

4)interact交互

interact :执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有
这一句登录完成后会退出,而不是留在远程终端上。

[root@egon ~]# cat test.sh
#!/usr/bin/expect -f
spawn ssh root@192.168.12.20
expect {
  "yes/no" {send "yes
";exp_continue}
  "*assword" {send "1
"}
}
interact
[root@egon ~]#
[root@egon ~]# ./test.sh
spawn ssh root@192.168.12.20
root@192.168.12.20's password:
Last login: Wed Aug 26 21:28:04 2020 from egon
+--------------------------------------------+
|                       |
|   你当前登录的是支付业务后台数据库服务   |
|   请不要删库                |
|                       |
+--------------------------------------------+
[root@egon ~]# pwd
/root
[root@egon ~]# echo "hello"
hello
[root@egon ~]# exit
登出
Connection to 192.168.12.20 closed.
[root@egon ~]#

三、expect脚本传参

shell脚本中的变量无法直接在expect中使用的,若expect需要使用变量一方面可以自己定义

#!/usr/bin/expect -f
set timeout -1
set user "root"
set ip "192.168.12.20"
set cmd "hostname"
set pass "1"
spawn ssh $user@$ip $cmd
expect {
  "yes/no" {send "yes
";exp_continue}
  "*assword" {send "$pass
"}
}
expect eof

另外一方面可以通过下述方式引入shell变量,注意此时解释器换成#!/bin/bash

#!/bin/bash
user="root"
ip="192.168.12.20"
cmd="hostname"
pass="1"
expect << EOF
spawn ssh $user@$ip $cmd
expect {
  "yes/no" {send "yes
";exp_continue}
  "*assword" {send "$pass
"}
}
expect eof
EOF
此外,expect脚本还可以从命令行获取参数
在expect中, $argc 表示参数个数,而参数值存放在 $argv 中,比如取第一个参数就是 [lindex
$argv 0] ,以此类推。

[root@egon ~]# cat test.sh
#!/usr/bin/expect -f
if {$argc != 4} {
  puts "Usage:./script.sh <ip> <username> <password> <cmd>"
  exit 1
}
set ip [lindex $argv 0]
set user [lindex $argv 1]
set pass [lindex $argv 2]
set cmd [lindex $argv 3]
set timeout -1
spawn ssh $user@$ip $cmd
expect {
  "yes/no" {send "yes
";exp_continue}
  "*assword" {send "$pass
"}
}
expect eof
[root@egon ~]# ./test.sh
Usage:./script.sh <ip> <username> <password> <cmd>
[root@egon ~]# ./test.sh 192.168.12.20 root 1 hostname
spawn ssh root@192.168.12.20 hostname
root@192.168.12.20's password:
egon
[root@egon ~]#

四、grep介绍

1)grep简介

grep命令主要用于过滤文本,grep家族如下
	1)grep: 在文件中全局查找指定的正则表达式,并打印所有包含该表达式的行
	2)egrep:扩展的egrep,支持更多的正则表达式元字符
	3)fgrep:固定grep(fixed grep),有时也被称作快速(fast grep),它按字面解释所有的字符

2)grep命令格式

grep [选项] PATTERN 文件1 文件2 ...
[root@egon ~]# grep 'root' /etc/passwd
[root@egon ~]# fgrep 'bash' /etc/passwd
找到: grep返回的退出状态为0
没找到: grep返回的退出状态为1
找不到指定文件:  grep返回的退出状态为2

grep 命令的输入可以来自标准输入或管道,而不仅仅是文件,例如:
ps aux |grep 'nginx'

五、grep选项

-n, --line-number 在过滤出的每一行前面加上它在文件中的相对行号
-o, --only-matching 只显示匹配的内容
-q, --quiet, --silent 静默模式,没有任何输出,得用$?来判断执行成功没有,即有没有过滤
到想要的内容
--color 颜色
-i, --ignore-case 忽略大小写
-A, --after-context=NUM 如果匹配成功,则将匹配行及其后n行一起打印出来
-B, --before-context=NUM 如果匹配成功,则将匹配行及其前n行一起打印出来
-C, --context=NUM 如果匹配成功,则将匹配行及其前后n行一起打印出来
-c, --count 如果匹配成功,则将匹配到的行数打印出来
-v, --invert-match 反向查找,只显示不匹配的行
-w 匹配单词
-E 等于egrep,扩展
-l, --files-with-matches 如果匹配成功,则只将文件名打印出来,失败则不打印
通常-rl一起用,grep -rl 'root' /etc
-R, -r, --recursive 递归

六、grep示例

# 1、-n
[root@egon ~]# grep -n 'root' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
[root@egon ~]#
# 2、-o
[root@egon ~]# grep -o 'root' /etc/passwd
root
root
root
root
[root@egon ~]#
# 3、-q
[root@egon ~]# grep -q 'root' /etc/passwd
[root@egon ~]# echo $?
0
# 4、--color
[root@egon ~]# alias grep
alias grep='grep --color=auto'
[root@egon ~]#
# 5、-i
[root@egon ~]# echo "EGON" |grep -i egon
EGON
[root@egon ~]#
# 6、-A-B-C
[root@egon ~]# grep -A 2 'root' /etc/passwd
[root@egon ~]# grep -B 2 'root' /etc/passwd
[root@egon ~]# grep -C 2 'root' /etc/passwd
# 7、-c
[root@egon ~]# grep -c 'root' /etc/passwd
2
[root@egon ~]#
# 8、-v
[root@egon ~]# ps aux | grep nginx |grep -v grep
[root@egon ~]#
[root@egon ~]# ps aux | grep [n]ginx
[root@egon ~]#
# 9、-w
[root@egon ~]# netstat -an |grep -w 80
tcp6    0    0 :::80          :::*           LISTEN  
[root@egon ~]# netstat -an |grep '<80>'
tcp6    0    0 :::80          :::*           LISTEN  
[root@egon ~]# netstat -an |grep '80'
tcp6    0    0 :::80          :::*           LISTEN 
                     
# 10、-rl
[root@egon ~]# grep -rl 'root' /etc # 将/etc目录下所有包含'root'内容的文件都列出来

七、正则表达式

1)正则表达式介绍

1.正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),是计算机科学的一个概念。正则表达式由元字符组成,通常被用来检索、替换那些符合某个模式(规则)的文本(许多程序设计语言都支持利用正则表达式进行字符串操作)。

2.元字符:是一类可以表达出超越其字面本身含义的特殊字符
shell元字符(也称为通配符): 由shell解释器来解析,如rm -rf *.pdf,元字符*Shell将其解析为任意多个字符
正则表达式元字符 : 由各种执行模式匹配操作的程序来解析,比如vi、grep、sed、awk

3.例如:vim示例:
:1,$ s/tom/EGON/g # 如anatomy、tomatoes及tomorrow中的“tom”被替换了,而Tom确没
被替换
:1,$ s/<[Tt]om>/EGON/g

2)正则表达式元字符

元字符 功能  示例
^  行首 ^love
$  行尾 love$
.  除了换行符以外的任意单个字符 l..e
*  前导字符的零个或多个   ab*love
.*  所有字符 a.*love
[]  字符组内的任一字符 [lL]ove
[^]  对字符组内的每个字符取反(不匹配字符组内的每个字符)  [^a-z0-9]ove
^[^]    非字符组内的字符开头的行
[a-z]  小写字母
[A-Z]  大写字母
[a-Z]    小写和大写字母
[0-9]    数字
 用来转义元字符  love.
<   词首定位符 单词一般以空格或特殊字符做分隔、连续的字符组成  <love
> 词尾定位符  love>
(..)  匹配稍后将要使用的字符的标签         (love)able1er
:1,$ s/						(192.168.11).66/1.50/g
x{m} 字符x重复出现m次   e{3}
x{m,} 字符x重复出现m次以上 e{3,}
x{m,n} 字符x重复出现m到n次 e{3,6}

3)正则表达式示例

# 1、^ 行首
[root@egon ~]# grep '^root' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@egon ~]#
# 2、$ 行尾
[root@egon ~]# grep 'bash$' /etc/passwd
root:x:0:0:root:/root:/bin/bash
user1:x:1002:1003::/home/user1:/bin/bash
egon1:x:198:1005::/home/egon1:/bin/bash
gg:x:1004:1006::/home/gg:/bin/bash
egon:x:1005:1007::/home/egon:/bin/bash
tom:x:1006:1008::/home/tom:/bin/bash
[root@egon ~]#
# 3、. 除了换行符以外的任意单个字符
[root@egon ~]# grep 'r..t' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
[root@egon ~]#
# 4、* 前导字符的零个或多个
[root@egon ~]# cat a.txt
a
ab
abb
abbb
bbbbb
[root@egon ~]# grep 'ab*' a.txt
a
ab
abb
abbb
[root@egon ~]#
# 5、.* 所有字符=贪婪
[root@egon ~]# cat a.txt
a123+-*/c11113333c
a1c
a77Ac
a23333c
ac
111
222
333
[root@egon ~]# grep 'a.*c' a.txt
a123+-*/c11113333c
a1c
a77Ac
a23333c
ac
[root@egon ~]#
# 5.1 .*?=》非贪婪,默认情况下,grep不支持非贪婪修饰符,但您可以使用grep -P来使用Perl语法来
支持.*?
[root@egon ~]# cat a.txt
<a href="http://www.baidu.com">"我他妈的是百度"</a>
<a href="http://www.sina.com.cn">"我特么的是新浪"</a>
[root@egon ~]#
[root@egon ~]# grep -o 'href=".*"' a.txt # 贪婪
href="http://www.baidu.com">"我他妈的是百度"
href="http://www.sina.com.cn">"我特么的是新浪"
[root@egon ~]#
[root@egon ~]# grep -oP 'href=".*?"' a.txt # 非贪婪
href="http://www.baidu.com"
href="http://www.sina.com.cn"
[root@egon ~]#
# 6、[] 字符组内的任一字符
# 7、[^] 对字符组内的每个字符取反(不匹配字符组内的每个字符)
[root@egon ~]# cat a.txt
a1c
a2c
a33c
aAc
aZc
[root@egon ~]# grep 'a[0-9]c' a.txt
a1c
a2c
[root@egon ~]# grep 'a[^0-9]c' a.txt
aAc
aZc
[root@egon ~]#
[root@egon ~]# grep 'a[0-9][0-9]c' a.txt
a33c
[root@egon ~]#
# 8、^[^] 非字符组内的字符开头的行
[root@egon ~]# cat a.txt
a1c
a2c
a33c
aAc
aZc
[root@egon ~]# grep '^[^0-9]..$' a.txt
a1c
a2c
aAc
aZc
[root@egon ~]#
# 9、[a-z] 小写字母
# 10、[A-Z] 大写字母
# 11、[a-Z] 小写和大写字母
# 12、[0-9] 数字
# 13、< 单词头 单词一般以空格或特殊字符做分隔,连续的字符串被当做单词
# 14、> 单词尾
[root@egon ~]# netstat -an |grep -w 80
tcp6    0    0 :::80          :::*           LISTEN  
[root@egon ~]# netstat -an |grep '<80>'
tcp6    0    0 :::80          :::*           LISTEN  
[root@egon ~]# netstat -an |grep '80'
tcp6    0    0 :::80          :::*           LISTEN 
Ps: grep匹配换行符和制表符
[root@egon ~]# echo -e "a
b" |grep $'a
b'
a
b
[root@egon ~]#
[root@egon ~]# echo -e "a	b" |grep $'a	b'
a b
[root@egon ~]#

4)扩展正则元字符

# 扩展正则元字符
+ 匹配一个或多个前导字符  [a-z]+ove
? 匹配零个或一个前导字符  lo?ve
a|b 匹配a或b love|hate
() 组字符 love(able|rs) (egon)+
(..)(..)12 标签匹配字符 (love)able1er
x{n}   x出现n次   e{3}
x{n,}   x出现n次至无穷次  e{3,}
x{n,m}     x出现n次至m次  e{3,6}

# 若想使用扩展正则
grep加-E 或 egrep 或转义
sed 加 -r 参数 或转义
AWK 直接支持大多数扩展正则,更多支持需要加选项--posix选项

5)扩展元字符示例

# ======================grep扩展正则示例======================
[root@egon ~]# cat a.txt
a
ab
abb
abbb
abbbb
abbbbb
bbbbbbb
[root@egon ~]# grep 'ab{2,4}' a.txt # 默认不支持扩展正则,所以没效果
[root@egon ~]# egrep 'ab{2,4}' a.txt
abb
abbb
abbbb
abbbbb
[root@egon ~]#
# ======================sed扩展正则示例======================
[root@egon ~]# sed -n '/roo?/p' /etc/passwd # 默认不支持扩展正则?
[root@egon ~]# sed -n '/roo?/p' /etc/passwd # 可以用转义扩展正则符号?
有结果,结果略...
[root@egon ~]# sed -rn '/roo?/p' /etc/passwd # 也可以加-r选项
有结果,结果略...
[root@egon ~]#
# ======================awk扩展正则示例======================
[root@egon ~]# cat a.txt
a
ab
abb
abbb
abbbb
abbbbb
bbbbbbb
[root@egon ~]# awk '/ab{1,3}/{print}' a.txt
ab
abb
abbb
abbbb
abbbbb
[root@egon ~]# awk --posix '/ab{1,3}/{print}' a.txt
ab
abb
abbb
abbbb
abbbbb
[root@egon ~]#

6)总结

grep: 使用基本元字符集 ^, $, ., *, [], [^], < >,(),{}
egrep(或grep -E): 使用扩展元字符集 ?, +, { }, |, ( )
# 注:grep也可以使用扩展集中的元字符,仅需要对这些元字符前置一个反斜线
w 所有字母与数字,称为字符[a-zA-Z0-9]  'l[a-zA-Z0-9]*ve'  'lw*ve'
W 所有字母与数字之外的字符,称为非字符  'love[^a-zA-Z0-9]+'     'loveW+'
 词边界 'love'  '<love>'

7)POSIX定义的字符分类

# 表达式    功能               示例
[:alnum:]   字母与数字字符            [[:alnum:]]+ 
[:alpha:] 字母字符(包括大小写字母) [[:alpha:]]{4}
[:blank:]   空格与制表符             [[:blank:]]*
[:digit:]    数字字母              [[:digit:]]?
[:lower:]   小写字母              [[:lower:]]{5,}
[:upper:]   大写字母              [[:upper:]]+
[:punct:]   标点符号              [[:punct:]]
[:space:]   包括换行符,回车等在内的所有空白[[:space:]]+
# 详解
[:alnum:] Alphanumeric characters.
匹配范围为 [a-zA-Z0-9]
[:alpha:] Alphabetic characters.
匹配范围为 [a-zA-Z]
[:blank:] Space or tab characters.
匹配范围为 空格和TAB键
[:cntrl:] Control characters.
匹配控制键 例如 ^M 要按 ctrl+v 再按回车 才能输出
[:digit:] Numeric characters.
匹配所有数字 [0-9]
[:graph:] Characters that are both printable and visible. (A space is print-
able, but not visible, while an a is both.)
匹配所有可见字符 但不包含空格和TAB 就是你在文本文档中按键盘上能用眼睛观察到的所有符号
[:lower:] Lower-case alphabetic characters.
小写 [a-z]
[:print:] Printable characters (characters that are not control characters.)
匹配所有可见字符 包括空格和TAB
能打印到纸上的所有符号
[:punct:] Punctuation characters (characters that are not letter, digits, con-
trol characters, or space characters).
特殊输入符号 +-=)(*&^%$#@!~`|"'{}[]:;?/>.<,
注意它不包含空格和TAB
这个集合不等于^[a-zA-Z0-9]
[:space:] Space characters (such as space, tab, and formfeed, to name a few).
[:upper:] Upper-case alphabetic characters.
大写 [A-Z]
[:xdigit:] Characters that are hexadecimal digits.
16进制数 [0-f]
# 使用方法:
[root@egon ~]# grep --color '[[:alnum:]]' /etc/passwd

八、练习

目标文件/etc/passwd,使用grep命令或egrep
1.显示出所有含有root的行:
2.输出任何包含bash的所有行,还要输出紧接着这行的上下各两行的内容:
3.  显示出有多少行含有nologin。
4.显示出那些行含有root,并将行号一块输出。
5.显示出文件中
6.新建用户
  abominable
  abominate
  anomie
  atomize
  编写正则表达式,将他们匹配出来
  egrep 'a.omi(nabl|nat|z|)e' /etc/passwd
7.建四个用户
  Alex213sb
  Wpq2222b
  yH438PIG
  egon666
  egon
  过滤出用户名组成是字母+数字+字母的行
[root@MiWiFi-R3-srv ~]# egrep '^[a-Z]+[0-9]+[a-Z]+' /etc/passwd
8.显示出/etc目录下所有包含root的文件名
9. 过滤掉/etc/ssh/sshd_config内所有注释和所有空行
grep -v '^#' /etc/ssh/sshd_config |grep -v '^ *$'
原文地址:https://www.cnblogs.com/jhno1/p/14105381.html