grep
目的
- 过滤,查找文档中的内容
分类
-
grep
-
egrep
-
扩展支持正则
-
\w 所有字母与数字,称为字符[a-zA-Z0-9] ‘l[a-zA-Z0-9]*ve’ === ‘l\w*ve’
-
\W 所有字母与数字之外的字符,称为非字符 ‘love[^a-zA-Z0-9]+’ === ‘love\W+’
-
-
-
\b 词边界 ‘\<love\>’ === ‘\blove\b’
-
fgrep
- 就不支持正则
返回值
-
0 是找到了
- 表示成功;
-
1 是没有
- 表示在所提供的文件无法找到匹配的pattern
-
2 找到地儿不对
-
示范
## grep 'root' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
## echo $?
0
## grep 'root1' /etc/passwd #用户root1并不存在
## echo $?
1
## grep 'root' /etc/passwd1 #这里的/etc/passwd1文件并不存在
grep: /etc/passwd1: No such file or directory
## echo $?
2
参数
-
grep -q 静默
即不显示查找的结果
[root@localhost ~]# grep "5\.." 1.txt
5.1
5.2
5.a
5.b
5..
5...
5.aaa
[root@localhost ~]# grep -q "5\.." 1.txt
[root@localhost ~]# echo $?
0
- grep -v 取反
[root@localhost ~]# cat 1.txt
5.1
5.2
5.a
5.b
5..
5...
5.aaa
[root@localhost ~]# grep -v "5\.." 1.txt
5...
5.aaa
- grep -R 可以查目录下面的文件
[root@web shell02]# grep chenfuguo /etc/
grep: /etc/: 是一个目录
[root@web shell02]# grep -R chenfuguo /etc/
/etc/mtab:/dev/sr0 /run/media/chenfuguo/CentOS\0407\040x86_64 iso9660 ro,nosuid,nodev,relatime,uid=1000,gid=1000,iocharset=utf8,mode=0400,dmode=0500 0 0
- grep -o 只找到这个关键字就可以
[root@localhost ~]# grep "a" 1.txt
5.a
5.aaa
a
ab
abc
abcd
abcde
abcdef
loveable
ldfadasfsdave
[root@localhost ~]# grep -o "a" 1.txt
a
a
a
a
a
a
a
a
a
a
a
a
a
a
-
grep -B2前两行
-
grep -A2后两行
-
grep -C2上下两行
-
egrep -l 只要文件名
[root@localhost ~]# egrep -l 'root' /etc/passwd
/etc/passwd
- egrep -n 带行号
[root@localhost ~]# egrep -n 'xulei' /etc/passwd
43:xulei:x:1000:1000::/home/xulei:/bin/bash
sed
-
Stream EDitor:流编辑
-
sed 是一种在线的、非交互式的编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。
接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;
格式
-
**1 sed 选项 命令 文件 **
-
sed [options] ‘command’ file(s)
-
2 sed 选项 –f 脚本 文件
- sed [options] -f scriptfile file(s)
返回值
-
都是0,对错不管。
-
只有当命令存在语法错误时,sed的退出状态才是非0
sed和正则表达式
-
与grep一样,sed在文件中查找模式时也可以使用正则表达式(RE)和各种元字符。正则表达式是括在斜杠间的模式,用于查找和替换,以下是sed支持的元字符。
-
使用基本元字符集 ^, $, ., *, [], [^], < >,(),{}
使用扩展元字符集 ?, +, |, ( ) -
使用扩展元字符的方式:
-
\+ 转义
-
sed -r 加-r
-
删除命令: d
sed -r '哪些行(正则/行号)干什么(d/r/s/w等等)' 文件名
sed -r '3d' passwd.txt
sed -r '/^root/d' passwd.txt
通过正则匹配词组删除:
# red -ri '/root/d' passwd.txt # 选项加上i 表示要修改源文件
# sed -r '/root/d' passwd.txt
通过正则匹配词组删除
[root@localhost ~]# sed -r '/root/d' passwd
通过行号删除:
# sed -r '3d' passwd # 表示删除第三行
标准写法:
# sed -r '3{d}' passwd
# sed -r '3{d;}' passwd
{存放sed的多个命令} 3{h;d},h暂存空间
# sed -r '3,$d' passwd
$最后一行
删除3到最后一行
[root@localhost ~]# sed -r '3,$d' passwd
root:x:0:0:root:/root:/bin/bash1
bin:x:1:1:bin:/bin:/sbin/nologin2
替换命令: s
语法:
默认替换匹配行的第一个
# sed -r 's/要替换的内容/新的内容/' 文件名
全部替换
# sed -r 's/要替换的内容/新的内容/g' 文件名
# sed -r 's/root/aofa/g' passwd
全部的root被换掉了。
请思考与下面的命令有区别吗?
# sed -r 's/^root/aofa/' passwd
# sed -r 's/[0-9][0-9]$/&.5/' passwd
查找双数 结尾的词组
&:替换成 双数.5
&有查询结果的含义。
VI中也有类似功能。
:% s/.*/#&/g
&:查询结果的含义
:% s/\(.*\)/#\1/g
每一行
换成
#每一行
# sed -r 's/(mail)/E\1/g' passwd
()括号组合字符,\1调用括号
sed -r 's#(mail)#E\1#g' passwd
分隔符可以换成井号
读文件命令:r
在当前文件中,读取其他文件“部分”内容。
# sed -r '$r 1.txt' passwd
# 最后一行,读取新文件1.txt $表示最后一行 r表示读
# sed -r '/root/r ip.txt' passwd
正则搜寻root
在root后面读取新文件
写文件命令:w(另存为)
#####
```powershell
# sed -r 'w 111.txt' 1.txt
把1.txt全部内容 写入111.txt
#sed -r '/root/w 123.txt' passwd.txt
# 把包含root的行 写入123.txt文件中
# sed -r '1,5w 123.txt' passwd
把1到5行另存为123.txt
追加命令: a(之后)
# sed -r 'a123' passwd
每行后面,都加上123行
# red -r '/^root/a chen:123:x:x:123' passwd.txt
在以root开始的行后面,添加 chen:123:x:x:123
在第二行后面加上三行内容:
sed -r '2a 1111\
> 3333333\
> 444444' passwd
插入命令: i(之前)
# sed -r '2iaaaaaaaa' passwd
在第二行插入新行aaaaaaaaaa
替换整行命令: c
# sed -r '2caaaaaaaa' passwd
把第二行替换成aaaaaaaaa
一行替换多行
是将一行替换成,多行。
[root@localhost ~]# sed -r '2c3333\
> 44444' passwd
获取下一行命令:n
# sed -r '3{n;d}' passwd.txt
# 第三行的下一行,删除
{命令组合}
反向选择: !
sed -r '2,$d' passwd
sed -r '2,$!d' passwd
# 2到最后一行不删,即第一行删
多重编辑 e
sed -r -e '1,3d' -e '4s/adm/admin/g' passwd
二、awk
前言
awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。
它支持用户自定义函数和动态正则表达式等先进功能,
awk的处理文本和数据的方式:
它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。
如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),
awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,
分别是Alfred Aho、Peter Weinberger、 Kernighan。
工作原理
awk -F: '{print $1,$3}' /etc/passwd
(1)awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符结束
(2)然后,行被:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始,
最多达100个字段
(3)awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔
成字段并进行处理。该过程将持续到所有行处理完毕
示例:
# awk -F: '{print $0}' passwd.txt
# awk -F: '{print $1}' passwd.txt
# awk -F: '{print $2}' passwd.txt
# awk -F: '{print $3}' passwd.txt
语法
-
awk [options] ‘commands’ filenames (推荐)
-
options:
- 例如:-F 定义输入字段分隔符,默认的分隔符是空格或制表符(tab)
-
command(时空):
-
BEGIN{} {} END{}
-
-
BEGIN{}
- begin发生在行处理前(注意大写)
-
{}
- 行处理时,读一行执行一次
-
END{}
- 行处理后
-
-
示例
awk -F: 'BEGIN {print 1/2} {print $0} END {print "-------"} ' passwd.txt
awk -F: 'BEGIN {print "awk开始执行"} {print $0} END {print "awk执行结束"} passwd.txt
内部变量
FS
输入字段分隔符(默认空格)
[root@localhost ~]# awk -F: '{print $1, $3}' /etc/passwd | head -1
root 0
或
[root@localhost ~]# awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd | head -1
root x 0
或
[root@localhost ~]# awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd | head -1
root 0
*OFS
输出字段分隔符
[root@localhost ~]# awk -F: '{print $1,$2,$3,$4}' /etc/passwd | head -1
root x 0 0
[root@localhost ~]# awk -F: 'BEGIN{FS=":";OFS="+++"}{print $1,$2,$3,$4}' /etc/passwd | head -1
root+++x+++0+++0
RS(默认不要动)
输入记录(行)分隔符,默认换行符
[root@localhost ~]# awk '{print $0}' a.txt
111 222 333 444 555:666:777
[root@localhost ~]# awk 'BEGIN{RS=" "}{print $0}' a.txt
111
222
333
444
555:666:777
请注意,在此时记录已经不是行的概念了。分隔符由”换行符“换成了”空格“
ORS(默认不要动)
输出记录(行)分隔符,默认换行符
awk 'BEGIN {ORS="++++" } {print $0}' 1.txt
111++++222++++333++++444++++555++++
FNR
多文件独立编号。
即每个文件独立编号,如果一个文件里面混入的有其他文件,则单独设置编号
NR
多文件汇总编号
[root@localhost ~]# awk -F: '{print NR, $0}' /etc/centos-release /etc/hosts
1 CentOS Linux release 7.3.1611 (Core)
2 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
3 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@localhost ~]# awk -F: '{print FNR, $0}' /etc/centos-release /etc/hosts
1 CentOS Linux release 7.3.1611 (Core)
1 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
2 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
NF
字段总数
[root@localhost ~]# awk -F: '{print NF, $0}' /etc/passwd
7 root:x:0:0:root:/root:/bin/bash
7 bin:x:1:1:bin:/bin:/sbin/nologin
7 daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@localhost ~]# awk -F: '{print NF, $NF}' /etc/passwd
7 /bin/bash
7 /sbin/nologin
7 /sbin/nologin
格式化输出
print 函数
date |awk '{print "Month: " $2 "\nYear: " $1}'
Month: 07月
Year: 2024年
\n换行符
想输出文字,用引号
awk -F: '{print "username is: " $1 "\t uid is: " $3}' /etc/passwd | head -1
username is: root uid is: 0
awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd | head -1
username and uid: root 0!
模式(正则表达)和动作
概念
任何awk语句都由模式和动作组成。模式部分决定动作语句何时触发及触发事件。 如果省略模式部分,动作将时刻保持执行状态。每一行都会有动作。 模式可以是任何条件语句或复合语句或正则表达式。有模式的话,就是对模式对应的行进行动作。
模式:可以是条件测试,正则,复合语句
动作:可以是打印,计算等。
字符串比较
# awk '/^root/' /etc/passwd
# awk '$0 ~ /^root/' /etc/passwd # ~相当于=
# awk '$0!~/^root/' /etc/passwd
# awk -F: '$1 ~ /^root/' /etc/passwd
数值比较
目的:
比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作。比较表达式使用关系运算符, 用于比较数字与字符串。
关系运算符
语法:
运算符 含义 示例
< 小于 x<y
<= 小于或等于 x<=y
== 等于 x==y
!= 不等于 x!=y
>= 大于等于 x>=y
> 大于 x>y
示例:
# awk -F: '$3 == 0' /etc/passwd
# awk -F: '$3 == 1' /etc/passwd
# awk -F: '$3 < 10' /etc/passwd
== 也可以用于字符串判断
# awk -F: '$7 == "/bin/bash"' /etc/passwd
# awk -F: '$1 == "alice"' /etc/passwd
算术运算
语法:
+ - * / %(模) ^(幂2^3)
awk -F: '$3 * 10 > 100' /etc/passwd
多条件
逻辑操作符和复合模式
语法:
&& 逻辑与 a&&b
|| 逻辑或 a||b
! 逻辑非 !a
示例:
# awk -F: '$1~/root/ && $3<=15' /etc/passwd
# awk -F: '$1~/root/ || $3<=15' /etc/passwd
# awk -F: '!($1~/root/ || $3<=15)' /etc/passwd
范围模式
语法:
awk '/从哪里/,/到哪里/' filename
awk -F: '/adm/,/lpd/' /etc/passwd
从adm到ldp,显示出来,注意避免匹配重复的字段
awk脚本编程
变量
awk调用变量
自定义内部变量 -v:
awk -v user=root -F: '$1 == user' /etc/passwd
-v定义变量
外部变量 “ ‘ ” :
单引号
[root@localhost ~]# heihei=shutdown
[root@localhost ~]# echo $heihei
shutdown
[root@localhost ~]# awk -F: '$1 ~ "'"$heihei"'" ' passwd
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
注意使用单引号时,内部需要用双引转义
条件&判断
if语句
格式:
awk -F: '{if(表达式){语句;语句;...}}' 文件名
awk -F: '{ if($3==0){ print $1 "是超级管理员"} }' passwd.txt
root是超级管理员
awk -F: '{ if($3==0){ print $1 "是超级管理员"} else {print $1 "普通用户"} }' passwd.txt
root是超级管理员
bin普通用户
daemon普通用户
adm普通用户
lp普通用户
sync普通用户
shutdown普通用户
halt普通用户
mail普通用户
operator普通用户
if…else语句
格式:
awk -F: '{if(表达式){语句;语句;...}else{语句;语句;...}}' 文件名 {if(){}else{}}
awk -F: '{if($3==0){count++} else{i++}} END{print "管理员个数: "count ; print "系统用户数: "i}' /etc/passwd
if…else if…else语句
格式:
{if(表达式1){语句;语句;...}else if(表达式2){语句;语句;...}else if(表达式3){语句;语句;...}else{语句;语句;...}}
if (条件){动作}elseif(条件){动作}else{动作}
if(){}else if (){}else if(){}else{}
awk -F: '{if($3==0){print $1," is admin "}else if ($3>999){print $1," is user"}else {print $1, " is sofo user"}}' /etc/passwd
显示出三种用户的信息 管理员:管理员ID为0 内置用户:用户ID<1000 普通用户: 用户ID>999
循环
while
每行打印十次
awk '{i=1;while(i<=10){print $0;i++}}' passwd
for
循环打印5个数字:
awk 'BEGIN{for(i=1;i<=5;i++){print i} }'
不适用BEGIN可以吗?
{},和END{}可以吗?可以需要有文件。
awk -F: '{ for(i=1;i<=10;i++) {print $0} }' /etc/passwd
将每行打印10次
awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd
打印每一行的每一列
awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd
root
x
0
0
root
/root
/bin/bash
NF是最大列数,循环打印了每一列。
数组
定义数组
需求:将用户名定义为数组的值,打印第一个值
awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwd
root
数组遍历
按索引遍历
awk -F: '{username[x++]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd
10 games
11 ftp
12 nobody
13 systemd-bus-proxy
14 systemd-network
15 dbus
16 polkitd
30 chrony
17 abrt
31 ntp
18 unbound
awk编程案例
统计/etc/passwd中各种类型shell的数量
awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }' /etc/passwd
$NF 最后一列的字段内容
{}行处理
把统计的对象,作为索引。每次递增。
Print i 打印索引
Shells[i] 数组加索引,显示的就是值。