- 今日内容
- grep : 过滤
- sed :非交互式编辑文本
- awk :格式化处理有规律的文本
- expect : expect帮忙处理交互
三剑客命令的共性 :
1. 都支持正则表达式
2. 都支持管道
- 非交互式改密码
echo 123 | passwd nana --stdin
# Changing password for user egon.
# passwd: all authentication tokens updated successfully.
grep命令
grep命令主要用于过滤文本,grep家族如下:
grep:在文件中全局查找指定的正则表达式,并打印所有包含该表达式的行
egrep:扩展的egrep,支持更多的正则表达式元字符
fgrep:固定grep(fixed grep),有时也被称作快速(fast grep),它按字面解释是所有的字符
- grep运行原理
方式1 : 直接从文件中过滤
grep "root" /etc/passwd
# root:x:0:0:root:/root:/bin/bash
方式2 : 通过管道进行过滤
cat /etc/passwd | grep "root"
tasklist | findstr cmd windows系统中也可以通过管道进行过滤(findstr=grep)
打开文件,每读一行,都用正则表达式去匹配一下,但凡匹配成功一次,该行就被过滤出来
- grep的选项
head -10 /etc/passwd > test.txt
-n 过滤结果带有行号
grep -n "root" test.txt
# 1:root:x:0:0:root:/root:/bin/bash
# 10:operator:x:11:0:operator:/root:/sbin/nologin
-o 只显示匹配成功的内容
grep -o "root" test.txt
# root
# root
# root
# root
-q 静默输出(grep会默认把结果输出在终端,静默输出适用于写脚本文件)
vim test.txt
方法1 : grep "root" /etc/passwd &>/dev/null
方法2 : grep -q "root" /etc/passwd
if [ $? -eq 0 ];then
echo "ok"
else
echo "no"
fi
./a.txt
# ok
--color 输出结果加颜色
alias grep grep命令默认输出结果是自带颜色的
# alias grep='grep --color=auto'
-i 忽略大小写
grep -i "root" test.txt
# ROOT:x:0:0:root:/root:/bin/bash
# operator:x:11:0:operator:/Root:/sbin/nologin
-A 2 过滤成功的后两行显示
grep -A 2 "root" test.txt
# ROOT:x:0:0:root:/root:/bin/bash
# bin:x:1:1:bin:/bin:/sbin/nologin
# daemon:x:2:2:daemon:/sbin:/sbin/nologin
-B 2 过滤成功的前两行显示
grep -B 2 "root" test.txt
# halt:x:7:0:halt:/sbin:/sbin/halt
# mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
# operator:x:11:0:operator:/root:/sbin/nologin
-C 2 过滤成功的前后两行都显示
grep -C 2 "root" test.txt
# bin:x:1:1:bin:/bin:/sbin/nologin
# daemon:x:2:2:daemon:/sbin:/sbin/nologin
# root:x:3:4:adm:/var/adm:/sbin/nologin
# lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
# sync:x:5:0:sync:/sbin:/bin/sync
-c 显示过滤成功的行数
grep -c "root" test.txt
# 3
-v 取反
grep -v "root" test.txt 显示除了包含root以外的其他所有行
# bin:x:1:1:bin:/bin:/sbin/nologin
# daemon:x:2:2:daemon:/sbin:/sbin/nologin
-w 匹配单词
ps -ef | grep ssh 匹配所有包含ssh的进程
# root 1376 1 0 15:26 ? 00:00:00 /usr/sbin/sshd -D
# root 1623 1376 0 15:26 ? 00:00:00 sshd: root@pts/0
# root 1659 1625 0 15:27 pts/0 00:00:00 grep --color=auto ssh
ps -ef | grep -w ssh 匹配所有包含ssh单词的进程
# root 1663 1625 0 15:28 pts/0 00:00:00 grep --color=auto -w ssh
-l 匹配成功,则只将文件名打印出来,失败则不打印(通常-rl一起用)
-R,-r 递归
grep -rl "passwd" /etc 显示/etc目录下包含passwd字符串的文件名
# /etc/login.defs
# /etc/selinux/semanage.conf
# /etc/selinux/targeted/contexts/files/file_contexts
正则表达式
- 正则表达式 :用特殊的符号指定规则
^ 以什么开头开始匹配(只匹配开头)
grep -n "^root" test.txt
# 4:root:x:3:4:adm:/var/adm:/sbin/nologin
$ 从结尾结尾开始匹配(只匹配结尾)
grep -n "root$" test.txt
# 5:lp:x:4:7:lp:/var/spool/lpd:/sbin/root
cat c.txt
# abc
# a+c
# a-c
# a1c
# aaaaaac
# abbbbcc
# ccacccc
# dddddab
. 匹配任意一个字符
grep "a.c" c.txt
# abc
# a+c
# a-c
# a1c
# aaaa(aac)
# cc(acc)cc
* 左边的个字符出现0次或者无数次
grep "ab*" c.txt
# (ab)c
# (a)+c
# (a)-c
# (a)1c
# (aaaaaa)c
# (abbbb)cc
# cc(a)cccc
# ddddd(ab)
.* 匹配没有或者所有(贪婪模式)
grep "a.*c" c.txt
# abc
# a+c
# a-c
# a1c
# aaaaaac
# abbbbcc
# cc(acbcc) 贪婪模式,以最远的c为准
.*? 非贪婪模式
vim d.txt 需求 : 过滤出域名
< a href="www.baidu.com">我是百度</ a>< a href="http://www.sina.com.cn">新浪</ a>
grep -oP '".*?"' d.txt -o(只显示匹配成功的内容) -P(显示非贪婪模式的结果) .*?(固定用法,将贪婪模式变成非贪婪模式)
# "www.baidu.com"
# "http://www.sina.com.cn"
[] 匹配指定范围的任意一个字符
grep "a[a-zA-Z]c" c.txt 匹配a和c之间,包含的任意一个字符(不区分大小写)
# abc
# aaaaaac
注意 : -号只能放在最左边或者最右边 ; ^号在[]里面表示取反的意思
+ 左边的字符出现1次或者无穷次,(扩展政策,只能配合egrep一起使用)
egrep -n "ab+" c.txt
# 1:abc
# 6:aaabbbbcc
# 8:dddddab
注意 : * 号与 + 号的差别,*号表示左边的字符出现0次或者无穷次
- 案例
- 需求:判断用户输入的是否是数字
vim test.txt
# !/bin/bash
while true
do
read -p "输入年龄" age
if [[ $age =~ ^[0-9]+$ ]];then 判断正则必须加[],等于正则表达式=~,以数字开头以数字结尾(数字出现一次或者无穷次)
echo "pass"
break
else
echo "输入数字啊,弟弟"
fi
done
echo "后续代码"
sed命令
- sed常用的场景
场景1:
定位到某一行,然后将该行的某一部分给替换掉
- 格式
sed -r "定位 + 操作" test.txt
sed -r "3 操作" test.txt 定位到第3行进行操作
sed -r "3,5 操作" test.txt 定位到第3行到第5行进行操作
sed -r "1 操作;3操作" test.txt 定位到第1行和第3行进行操作
场景2:
定位到某一行,然后删除
sed -r "1,3d" test.txt 删除第1行到第3行
场景3:
定位到某一行,在该行下一行添加新的内容
sed -r "1a 123" test.txt 在第一行的下一行写入123
场景4:
定位到某一行,将整行替换掉
sed -r "1c aaa" test.txt 将第一行的内容替换成aaa
- sed(流逝编辑器) 底层原理
从硬盘把文件内容(一行一行读取)读入到内存,在内存中根据你制定的规则修改原文件。
修改好原文件后把结果输出到终端。默认情况下是不修改原文件!!!(修改原文件内容需要加选项 -i )
- sed命令使用
1. 通过行号来进行定位
cat test.txt
# xxxnanaxxxxnanaxxx
# NAnaxxxxNANAxxxxxx
# xnanaxxxxxnanaxxxx
# NANAxxxxNANaxxxxxx
s/old/new/gi i(忽略大小写),g(从左一直匹配到右)
sed -r "2s/nana/666/gi" test.txt 将第二行的nana替换成666
# xxxnanaxxxxnanaxxx
# 666xxxx666xxxxxx
# xnanaxxxxxnanaxxxx
# NANAxxxxNANaxxxxxx
sed -r "2,4s/nana/666/gi" test.txt 将第二行到第四行的nana替换成666
# xxxnanaxxxxnanaxxx
# 666xxxx666xxxxxx
# x666xxxxx666xxxx
# 666xxxx666xxxxxx
sed -r "2s/nana/666/gi;4s/nana/666/gi" test.txt 将第二行和第四行的nana替换成666
# xxxnanaxxxxnanaxxx
# 666xxxx666xxxxxx
# xnanaxxxxxnanaxxxx
# 666xxxx666xxxxxx
2. 通过正则来进行定位(针对一些不规律的配置文件)
cat test.txt
# 1xxxnanaxxxxnanaxxx
# 2NAnaxxxxNANAxxxxxx
# xnanaxxxxxnanaxxxx
# 4NANAxxxxNANaxxxxxx
sed -r "/^[a-zA-Z]/s/nana/666/gi" test.txt 将以字母开头的行nana替换成666
# 1xxxnanaxxxxnanaxxx
# 2NAnaxxxxNANAxxxxxx
# x666xxxxx666xxxx
# 4NANAxxxxNANaxxxxxx
- 删除
sed -r "1,3d" test.txt 删除第一行到第三行
# 4NANAxxxxNANaxxxxxx
sed -r "/^[0-9]/d" test.txt 删除以数字开头的行
# xnanaxxxxxnanaxxxx
- 定位行的下一行添加内容
sed -r "1a 123" test.txt
# 1xxxnanaxxxxnanaxxx
# 123
# 2NAnaxxxxNANAxxxxxx
# xnanaxxxxxnanaxxxx
# 4NANAxxxxNANaxxxxxx
- 替换定位行的内容
sed -r "1c aaa" test.txt
# aaa
# 2NAnaxxxxNANAxxxxxx
# xnanaxxxxxnanaxxxx
# 4NANAxxxxNANaxxxxxx
awk命令
- 格式
awk -F: 'NR==定位的行号{操作}' 文件路径
awk -F: 'NR>行号 && NR<行号{操作}' 文件路径
awk -F: 'NR==行号 || NR==行号{操作}' 文件路径
-F 指定分隔符(不写默认为空格)
注意 : 我们在指定文件的行号和操作时,只能使用单引号。
1. 指定行来进行定位
awk -F: 'NR==3{print $1,$7}' /etc/passwd 指定第三行,以:进行分割,打印第1段和第7段的内容
# daemon /sbin/nologin
awk -F: 'NR>3 && NR<5{print $0}' /etc/passwd 指定大于第三行,小于第五行,以:进行分割,打印整行内容($0,代表打印整行)
# adm:x:3:4:adm:/var/adm:/sbin/nologin
awk -F: 'NR==3 || NR==5{print $1}' /etc/passwd 指定第三行或者第五行,以:进行分割,打印第1段内容
# daemon
# lp
awk -F: 'NR==3 || NR==5{print $1"-"$3}' /etc/passwd 指定第三行或者第五行,以:进行分割,打印第1段和第3段的内容,中间以-进行连接
# daemon-2
# lp-4
注意 : || 符号,如果指定的行都存在,那就都进行操作;如果指定的行不存在,那就操作存在的行
2. 通过正则来进行定位
awk -F: '/bash$/{print $0}' /etc/passwd 打印以bash结尾,以:进行分割的行
# root:x:0:0:root:/root:/bin/bash
# egon:x:1000:1000::/home/egon:/bin/bash
- 案例
ifconfig eth0
# eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
# inet 192.168.80.100 netmask 255.255.255.0 broadcast 192.168.80.255
# inet6 fe80::1af5:8729:4b78:31f1 prefixlen 64 scopeid 0x20<link>
# ether 00:0c:29:ca:a8:27 txqueuelen 1000 (Ethernet)
# RX packets 13062 bytes 1012632 (988.8 KiB)
# RX errors 0 dropped 0 overruns 0 frame 0
# TX packets 6938 bytes 922523 (900.9 KiB)
# TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- 过滤出ifconfig eth0的IP地址
方法1:
ip=$(ifconfig eth0 | awk 'NR==2 {print $2}') 不写-F选项默认以空格为切割
echo $ip
# 192.168.80.100
方法2:
ip=$(ifconfig eth0 | awk '/netmask/{print $2}') 注意:匹配字符串不能在字符串中再加引号
echo $ip
# 192.168.80.100
expect命令
- 帮忙处理交互
- 免交互编写配置文件
cat>b.txt<<EOF
> 123
> 456
> 789
> EOF
cat b.txt
# 123
# 456
# 789
通过免交互的模式向b.txt中写入数据,输入EOF退出并保存
- 免交互执行ssh,远程登陆其他服务器配置文件模板
expect << EOF
spawn ssh $user@$ip $cmd
# 只要是spawn提交的命令都会交给expect软件执行
expect {
"yes/no" {send "yes\r";exp_continue}
# send会自动帮忙提交yes,\r换行符;exp_continue表示继续进行下一步
"*assword" {send "$password\n"}
# send会自动帮忙提交passwd,\n换行符
}
expect eof
EOF
- 修改其他虚拟机的主机名
1. 安装expect命令
yum -y install expect
2. 写入配置文件
vim a.sh
user="root"
ip="192.168.80.120"
cmd="hostname"
passwd=123
expect << EOF
spawn ssh root@192.168.80.120 hostname
expect {
"yes/no" {send "yes\r";exp_continue}
"*assword" {send "123\n"}
}
expect eof
EOF
./a.sh
# spawn ssh root@192.168.80.120 hostname
# root@192.168.80.120's password:
# svr7