前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux正则与文本处理工具

Linux正则与文本处理工具

作者头像
微软技术分享
修改2023-01-26 19:34:45
2.4K0
修改2023-01-26 19:34:45
举报

正则表达式 (Regular Expression, RE, 或称为常规表达式)是通过一些特殊字符的排列,用于『查找/替换/删除』一行或多行文字或字符串,简单的说,正则表达式就是用在字串的处理上面的一种『表示公式』,正则表达式并不是一个工具程序,而是一个对字符串处理的标准依据,如果您想要以正则表达式的方式处理字串,就得要使用支持正则表达式的工具程序才行,这类的工具程序很多,例如 vi,vim,sed,awk,gawk,egrep等.

正则表达式,对于系统管理员来说是非常重要的,因为系统会产生很多的信息,这些信息有的重要有的仅是警告,此时管理员可以通过正则表达式来过滤出相应的我们需要的字段,你最好掌握这门技术,会对将来的数据分析,主机管理起到很大的帮助.

基础正则表达式

在上一章说过正则表达式和通配符的区别,(正则表达式用来在文件中匹配符合条件的字符串,而通配符则是用来匹配符合条件的文件名)吗? 其实这种区别只在Shell当中适用,因为用来在文件当中搜索字符串的命令,如 grep、awk、sed 等命令可以支持正则表达式,而在系统当中搜索文件的命令,如 ls、find、cp 这些命令不支持正则表达式,所以只能使用shell自己的通配符来进行匹配了.

首先我们先来学习一下基础的正则表达式吧,下面是我们常用的正则语法,我会给每一个语法,举一个小例子,下面我们开始学习吧.

实例1: 使用 * 实现匹配前一个字符出现0次或任意多次(本例中,则是匹配g字符出现0次或任意多次)

代码语言:javascript
复制
[root@localhost ~]# ls
wang  wangg  wanggg

[root@localhost ~]# ls | grep "wang*"
wang
wangg
wanggg
[root@localhost ~]# ls | grep "wan*g*"
wang
wangg
wanggg

实例2: 使用 . 实现匹配除换行符以外的任意一个字符,(只匹配一个字符),一般我们把它叫做贪婪匹配

代码语言:javascript
复制
[root@localhost ~]# ls
wang  wangg  wanggg wangr

[root@localhost ~]# ls | grep "wang"
wang
[root@localhost ~]# ls | grep "wang."
wangg
wangr
[root@localhost ~]# ls | grep "wang.."
wanggg

实例3: 使用 ^ 实现匹配行首是指定字符的行

代码语言:javascript
复制
[root@localhost ~]# ls
alert  lyshark  tcpl  wakaka  wang  wangg  wanggg  woxin

[root@localhost ~]# ls | grep "^ly"
lyshark
[root@localhost ~]# ls | grep "^wa"
wakaka
wang
wangg
wanggg
[root@localhost ~]# ls | grep "^a"
alert

实例4: 使用 $ 实现匹配行尾是指定字符的行

代码语言:javascript
复制
[root@localhost ~]# ls
alert  lyshark  tcpl  wakaka  wang  wangg  wanggg  woxin

[root@localhost ~]# ls | grep "a$"
wakaka
[root@localhost ~]# ls | grep "ark$"
lyshark
[root@localhost ~]# ls | grep "^w" | grep "n$"     #匹配开头是w结尾是n的
woxin

实例5: 使用 [] 实现匹配中括号内任意一个字符,(只匹配其中一个)

代码语言:javascript
复制
[root@localhost ~]# ls
ale1t  ale2t  ale3t  aleat  alebt  alert

[root@localhost ~]# ls | grep "ale[a-z]t"
aleat
alebt
alert
[root@localhost ~]# ls | grep "ale[0-9]t"
ale1t
ale2t
ale3t
[root@localhost ~]# ls | grep "ale[ab]t"
aleat
alebt

实例6: 使用 [^] 实现匹配除了中括号字符以外的任意一个字符(^取反的意思)

代码语言:javascript
复制
[root@localhost ~]# ls
ale1t  ale2t  ale3t  aleat  aleAt  aleBB  alebt  aleCT  aleEt  alert

[root@localhost ~]# ls | grep "ale[^0-9]t"
aleat
aleAt
alebt
aleEt
alert
[root@localhost ~]# ls | grep "ale[^A-Z]t"
ale1t
ale2t
ale3t
aleat
alebt
alert
[root@localhost ~]# ls | grep "ale[^AE]t"
ale1t
ale2t
ale3t
aleat
alebt
alert

实例7: 使用 ^[^] 实现匹配行首是与不是指定字符的行

代码语言:javascript
复制
[root@localhost ~]# ls
ale1t  ale2t lyshark  tcpl  wakaka  wang  wangg  wanggg  woxin

[root@localhost ~]# ls | grep ^[a]        #匹配行首是a开头的
ale1t
ale2t
[root@localhost ~]# ls | grep ^[^a]       #匹配行首不是a开头的
lyshark
tcpl
wakaka
wang
wangg
wanggg
woxin

实例8: 使用 \{n}\ 实现匹配前面的字符恰好出现了n次的行

代码语言:javascript
复制
[root@localhost ~]# ls
12333  13466614578  13562653874  172.168.1.2  18264758942  192.168.1.1  45666  78999

[root@localhost ~]# ls | grep "123\{3\}"
12333
[root@localhost ~]# ls | grep "[0-9][0-9][0-9]\{3\}"    #匹配前两个字符是0-9的,最后一个字符出现过3次的
12333
45666
78999
[root@localhost ~]# ls | grep "[1][3-8][0-9]\{9\}"       #匹配手机号规则
13466614578
13562653874
18264758942

实例9: \{n,}\ 实现匹配前面的字符的出现,不小于n次的行

代码语言:javascript
复制
[root@localhost ~]# ls
12333  123333  1233333

[root@localhost ~]# ls | grep "123\{3,\}"               #前一个字符3的出现不小于3次
12333
123333
1233333
[root@localhost ~]# ls | grep "123\{4,\}"               #前一个字符3的出现不小于4次
123333
1233333

实例10: \{n,m}\ 实现匹配前面的字符出现,不小于n次,最多出现m次的行

代码语言:javascript
复制
[root@localhost ~]# ls
123  1233  12333  123333  1233333  12333333  123333333  1233333333  12333333333

[root@localhost ~]# ls |grep "123\{3,5\}"              #前一个字符3最少出现3次,最多不大于5次
12333
123333
1233333

总结:匹配一个合法IP地址

代码语言:javascript
复制
[root@localhost ~]# ls
10.10.10.22  127.9.0.8    172.168.1.2  192.168.1.1  192.168.1.3      255.255.255.255
127.0.0.1    172.168.1.1  172.168.1.3  192.168.1.2  192.199.256.256  256.256.256.256

[root@localhost ~]# ls | egrep "^(([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|
2[0-4][0-9]|25[0-4])$"

10.10.10.22
172.168.1.1
172.168.1.2
172.168.1.3
192.168.1.1
192.168.1.2
192.168.1.3

总结:匹配一个合法邮箱地址

代码语言:javascript
复制
[root@localhost ~]# ls
1181506874@qq.com  lysharks@163.cn  lysharks@163.com  wangrui@126.com  wangrui@129.cc

[root@localhost ~]# ls | egrep "^[0-9a-zA-Z][0-9a-zA-Z_]{1,16}[0-9a-zA-Z]\@[0-9a-zA-Z-]*([0-9a-zA-Z])?\.(com|com.cn|net|
org|cn)$"

1181506874@qq.com
lysharks@163.cn
lysharks@163.com
wangrui@126.com

扩展正则表达式

事实上,一般用户只要了解基础型的正则语句就已经相当足够了,不过,在某些时候,为了简化命令的长度,还是需要扩展正则的支持的,打个比方,我们可以使用 cat xxx.log | grep -v '^' |grep -v '^#' 来实现过滤文本中的注释行,和空白行,但是这不够精简,它的执行还是会用到两次的过滤,如果使用扩展正则表达式,我们可以这样写,cat xxx.log |egrep -v '^|^#' 这样一个命令就可实现上面的效果啦,此处我们需要说明的是,grep -E 和egrep效果是相同的,使用哪一个都一个样.

熟悉了基础正规表达式之后,再来看这个扩展正则表达式,是不是很轻松啊,亲,下面我们就来分别说明这几个符号的使用规则吧.

实例1: + 实现匹配前一个字符出现1次或任意多次

代码语言:javascript
复制
[root@localhost ~]# ls
gogle  google  gooogle  gooogooogle  goooogle  gooooogle  goooooogle

[root@localhost ~]# ls | grep -E "go+gle"
gogle
google
gooogle
goooogle
gooooogle
goooooogle

实例2: ? 实现匹配前一个字符出现0次,或1次

代码语言:javascript
复制
[root@localhost ~]# ls
gogle  google  gooogle  gooogooogle  goooogle  gooooogle  goooooogle

[root@localhost ~]# ls | grep -E "go?gle"
gogle
[root@localhost ~]# ls | grep -E "goo?gle"
gogle
google

实例3: | 实现匹配两个或多个分支选择

代码语言:javascript
复制
[root@localhost ~]# ls
alert  lyshark  rui  wang

[root@localhost ~]# ls | grep -E "alert|lyshark"
alert
lyshark
[root@localhost ~]# ls | grep -E "wang|rui|alert"
alert
rui
wang

实例4: () 实现将字符作为一个整体匹配,即模式单元

代码语言:javascript
复制
[root@localhost ~]# ls
dog  dogdog  dogdogdog  hello_lyshark  hello_world

[root@localhost ~]# ls | grep -E "(dog)+"
dog
dogdog
dogdogdog
[root@localhost ~]# ls | grep -E "hello_(world|lyshark)"
hello_lyshark
hello_world

Grep 行处理工具

grep (global search regular expression(RE) and print out the line 全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来,好了废话不多说,先看命令格式.

代码语言:javascript
复制
[root@localhost ~]# grep --help

命令语法:[ grep [选项] [过滤菜单] 文件名 ]

        -a              #将二进制数据一同列出
        -c              #计算找到查找字符串的次数
        -i              #忽略大小写差异
        -n              #顺便标号显示
        -v              #反选参数
        -q              #不显示任何提示信息,安静模式
        -E              #使用扩展正则,egrep
        -A              #匹配指定字符的后n个字符
        -B              #匹配指定字符的前n个字符
        -C              #匹配指定字符的前n个和后n个字符

实例1: 使用 grep -n 参数过滤数据时,一同标号

代码语言:javascript
复制
[root@localhost ~]# cat /etc/passwd | grep -n "root"

1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin

实例2: 使用 grep -v 反选打印,行中不包括/bin/bash的行

代码语言:javascript
复制
[root@localhost ~]# cat /etc/passwd | grep -vn "/bin/bash"

2:bin:x:1:1:bin:/bin:/sbin/nologin
3:daemon:x:2:2:daemon:/sbin:/sbin/nologin
4:adm:x:3:4:adm:/var/adm:/sbin/nologin
5:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6:sync:x:5:0:sync:/sbin:/bin/sync
7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8:halt:x:7:0:halt:/sbin:/sbin/halt
....省略....

实例3: 使用 grep -i 过滤出不论大小写的lyshark单词的行

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
LyShark
lyshark
admin
Admin
ADMIN
Good
GOOD

[root@localhost ~]# cat lyshark.log | grep -ni "lyshark"
1:LyShark
2:lyshark

实例4: 使用正则,过滤出开头是 ^L 的行的内容

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
LyShark
lyshark
admin
Admin
ADMIN
Good
GOOD

[root@localhost ~]# cat lyshark.log | grep -n "^L"
1:LyShark

实例5: 使用正则,过滤出开头不是 ^L的行的内容

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
LyShark
lyshark
admin
Admin
ADMIN
Good
GOOD

[root@localhost ~]# cat lyshark.log | grep -n "[^L]yshark"
2:lyshark

实例6: 使用正则,过滤出开头是小写字母的行

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
LyShark
lyshark
admin
Admin
ADMIN
Good
GOOD
123123
1233
66431
124adb

[root@localhost ~]# cat lyshark.log | grep -n "^[a-z]"
2:lyshark
3:admin

实例7: 使用正则,过滤出开头不是,a-z或A-Z的行

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
LyShark
lyshark
admin
Admin
ADMIN
Good
GOOD
123123
1233
66431
124adb

[root@localhost ~]# cat lyshark.log | grep -n "^[^a-zA-Z]"
8:123123
9:1233
10:66431
11:124adb

实例8: 使用正则,找出结尾是小数点的哪一行

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
LyShark
lyshark
admin
Admin
ADMIN
Good
123123
1233.
66431.

[root@localhost ~]# cat lyshark.log |grep -n "\.$"
8:1233.
9:66431.

实例9: 使用正则,过滤掉开头是#号的,和开头是空行的行

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
#LyShark
#lyshark
#admin
#Admin

ADMIN
Good

123123

1233.
66431.

[root@localhost ~]# cat lyshark.log | grep -v "^#" | grep -v "^$"
ADMIN
Good
123123
1233.
66431.

实例10: 使用正则,过滤出前一个字符o刚好出现两次的行

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
#LyShark
#lyshark
#admin
#Admin

ADMIN
Good
123123
1233.
66431.

[root@localhost ~]# cat lyshark.log |grep -n "o\{2\}"
7:Good

实例11: 使用正则,匹配开头是0-9且结尾是点的行

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
#LyShark
#lyshark
#admin
#Admin

ADMIN
Good
123123
1233.
66431.

[root@localhost ~]# cat lyshark.log |grep -n -E "^[0-9]+\."
9:1233.
10:66431.

实例12: 使用正则,匹配指定字符的后2个字符,或前2个字符

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
lyshark
LySHARK
wang
rui
hello
world
alert
123123
45678

[root@localhost ~]# cat lyshark.log |grep -n -A 2 "hello"
5:hello
6-world
7-alert

[root@localhost ~]# cat lyshark.log |grep -n -B 2 "hello"
3-wang
4-rui
5:hello

Cut 列提取工具

cut命令用来显示行中的指定部分,删除文件中指定字段,cut经常用来显示文件的内容,类似于type命令.该命令有两项功能,其一是用来显示文件的内容,它依次读取由参数file所指明的文件,将它们的内容输出到标准输出上.其二是连接两个或多个文件,如cut fl f2 > f3 将把文件fl和f2的内容合并,然后通过输出重定向符">" 的作用,将它们放入文件f3中.

首先我们来看一下它的格式吧,如下:

代码语言:javascript
复制
[root@localhost ~]# cut --help

命令语法:[ cut [选项] [列号] 文件名 ]

        -f              #-f 列号:指定提取第几列
        -d              #-d 分隔符:按照指定分隔符进行分割
        -c              #-c 字符范围:不依赖分割符来分割,而是通过字符范围进行字段提取
        -m              #表示从第一个字符提取到第m个
        -b              #仅显示行中指定直接范围的内容
        -n              #与"-b"选项连用,不分割多字节字符
        n-              #表示从第n个字符开始提取到结尾
        n-m             #表示从第n提取到第m个字符

        --complement    #补齐被选择的字节,字符或字段
        --out-delimiter=<字段分隔符> #指定输出内容是的字段分割符

手动创建一个文本,添加内容列之间用tab分隔,用来测试后续内容

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log

ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88

实例1: 通过使用 -f 选项指定过滤的列,并显示到屏幕

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log

ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88

[root@localhost ~]# cut -f 2 lyshark.log
NAME
WR
LC
LY

[root@localhost ~]# cut -f 2,5 lyshark.log
NAME    Mark
WR      100
LC      90
LY      88

实例2: 通过使用 --complement 选项提取指定字段之外的列,(打印除了第2列之外的列)

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log

ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88

[root@localhost ~]# cut -f 2 --complement lyshark.log

ID      AGE     Gender  Mark
1       22      m       100
2       26      m       90
3       23      m       88

实例3: 通过使用 -c 选项过滤/etc/passwd,并打印第1个到第3个字符

代码语言:javascript
复制
[root@localhost ~]# cut -c 1-3 /etc/passwd
roo
bin
dae
adm
lp:
syn
....省略....

实例4: 通过使用 -c -2 选项过滤/etc/passwd,并打印前2个字符

代码语言:javascript
复制
[root@localhost ~]# cut -c -2 /etc/passwd
ro
bi
da
ad
lp
....省略....

实例5: 通过使用 -c 5- 选项过滤/etc/passwd,打印从第5个字符开始到结尾

代码语言:javascript
复制
[root@localhost ~]# cut -c 5- /etc/passwd
:x:0:0:root:/root:/bin/bash
x:1:1:bin:/bin:/sbin/nologin
on:x:2:2:daemon:/sbin:/sbin/nologin
x:3:4:adm:/var/adm:/sbin/nologin
....省略....

实例6: 通过使用 -d 指定分隔符 -f 指定打印第个字段,以下我们分别截取第1和第7个字段

代码语言:javascript
复制
[root@localhost ~]# cut -d ":" -f 1,7 /etc/passwd
root:/bin/bash
bin:/sbin/nologin
daemon:/sbin/nologin
adm:/sbin/nologin
lp:/sbin/nologin
sync:/bin/sync
....省略....

实例7: 通过使用 -c -3 指定截取前3个字符,还可以通过 -c 3 截取第3个字符

代码语言:javascript
复制
[root@localhost ~]# cut -c -3 /etc/passwd
roo
bin
dae
adm
lp:
....省略....
[root@localhost ~]# cut -c 3 /etc/passwd
o
n
e
m
:
n
....省略....

Sed 流编辑器

sed是一种流编辑器,它是文本处理中非常中的工具,能够完美的配合正则表达式使用,功能不同凡响.处理时,把当前处理的行存储在临时缓冲区中,称为 "模式空间" (pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕,接着处理下一行,这样不断重复,直到文件末尾.文件内容并没有改变,除非你使用重定向存储输出.Sed主要用来自动编辑一个或多个文件,简化对文件的反复操作,编写转换程序等.

sed主要是来进行数据选取,替换,删除,新增的命令,二话不说先看一下它的参数吧.

代码语言:javascript
复制
[root@localhost ~]# sed --help

命令语法:[ sed [选项] [范围] [动作] 文件名 ]

        -n              #把经过sed命令处理的行输出到屏幕
        -e              #允许对输入数据应用多条sed命令编辑
        -f              #从sed脚本中读入sed操作,和awk命令的-f类似
        -r              #在sed中支持扩展正则表达式
        -i              #用sed的修改结果,写到文件

命令动作:

        p               #打印,输出指定的行
        a               #追加,在当前行后添加一行或多行
        i               #插入,在当前行前插入一行或多行
        c               #整行替换,用c后面的字符串替换原数据行
        d               #删除,删除指定的行
        s               #字串替换,格式:"行范围s/旧字串/新字串/g"

#对sed命令我们要知道的是,它所有的修改都不会直接修改文件的内容,而是在内存中进行处理然后打印到屏幕上
#如果想要写入文件,请使用 sed -i 选项才会保存到文本中.

在进行实验之前,首先创建一个文件,来做测试用

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log

ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

实例1: 使用 sed '2p' 重复打印第二行数据

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# sed '2p' lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
1       WR      22      m       100    ←本行是2p打印的
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# sed '3p' lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
2       LC      26      m       90     ←本行是2p打印的
3       LY      23      m       88
4       XDL     40      b       100

实例2: 使用 sed -n 限定,只选取指定的行进行显示

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# sed -n '2p' lyshark.log  ←只打印第2行数据
1       WR      22      m       100

[root@localhost ~]# sed -n '1p' lyshark.log  ←只打印第1行数据
ID      NAME    AGE     Gender  Mark

实例3: 使用 sed '2,4d' 删除掉文件2-4行,并显示到屏幕,(原文件内容并没有被修改)

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# sed '2,4d' lyshark.log   ←删除2-4行的数据并打印
ID      NAME    AGE     Gender  Mark
4       XDL     40      b       100

[root@localhost ~]# sed '1d' lyshark.log     ←删除第1行的数据
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

实例4: 使用 sed '2[a|i]' 追加,或者插入数据指定数据

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# sed '2a hello lyshark' lyshark.log      ←在第2行后面追加数据
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
hello lyshark
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# sed '2i hello lyshark' lyshark.log      ←在第2行前面插入数据
ID      NAME    AGE     Gender  Mark
hello lyshark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

实例5: 使用 \ 换行符,一次插入多行数据

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# sed '2a hello \    ←在第二行下面,插入一段话,用\隔开
> my name is lyshark \
> age 22 \
> boy ' lyshark.log

ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
hello
my name is lyshark
age 22
boy
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

实例6: 使用 sed 'c' 实现整行替换数据

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# cat lyshark.log | sed '5c 5    WRS    99    m    111'  ←整行替换第5行内容
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
5    WRS    99    m    111

实例7: 使用 sed 后面跟上 -i 选项,将第5行的修改,保存进文件,(-i选项是回写)

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# sed  -i '5c 5     WRS    99    m    111' lyshark.log

[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
5       WRS    99    m    111               ←这里的数据已经写入成功

实例8: 字符串的替换 sed 's/旧文本/新文本/g' 进行整行替换

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
5       WRS     99      m       111

[root@localhost ~]# sed '2s/WR/LyShark/g' lyshark.log   ←将第2行的,WR替换成LyShark
ID      NAME    AGE     Gender  Mark
1       LyShark 22      m       100
2       LC      26      m       90
3       LY      23      m       88
5       WRS     99      m       111

[root@localhost ~]# sed '3s/LC/Admin/g' lyshark.log     ←将第3行的,LC替换成Admin
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       Admin   26      m       90
3       LY      23      m       88
5     WRS    99    m    111

#注意:上方只是替换打印,并没有保存,如若想保存请加 -i 属性

实例9: 将第3行数据的开头添加#注释

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
5       WRS     99      m       111

[root@localhost ~]# sed '3s/^/#/g' lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
#2      LC      26      m       90
3       LY      23      m       88
5       WRS     99      m       111

实例10: 将第4和第5行的内容替换成空

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
5       WRS     99      m       111

[root@localhost ~]# sed -e '4s/LY//g ; 5s/WRS//g' lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3               23      m       88
5               99      m       111

#sed 要进行多行操作时,只能通过 -e 写多条操作语句,用 ; 或回车分隔

过滤IP地址小实验

代码语言:javascript
复制
[root@localhost ~]# ifconfig
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.10  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::897c:d72d:cd95:b9ec  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:b1:b7:be  txqueuelen 1000  (Ethernet)
        RX packets 2344  bytes 156370 (152.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 454  bytes 50049 (48.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@localhost ~]# ifconfig | grep "inet 192" |sed 's/^.*inet //g'
192.168.1.10  netmask 255.255.255.0  broadcast 192.168.1.255

[root@localhost ~]# ifconfig |grep "inet 192" |sed 's/^.*inet //g' |sed 's/ netmask.*$//g'
192.168.1.10

Printf 文本格式化

代码语言:javascript
复制
[root@localhost ~]# printf --help

输出类型:
        %ns:            #输出字符串,n是数字,指代输出几个字符
        %ni:            #输出证书,n是数字,指代输出几个数字
        %m.nf:          #输出浮点数,m和n是数字,指代输出整数位和小数位

输出格式:
        \a:             #输出警告音
        \b:             #输出退格键,也就是Backspace键
        \f:             #清屏
        \n:             #换行符
        \r:             #回车,也就是Enter键
        \t:             #水平输出退格键,也就是Tab键
        \v:             #垂直输出退格键,也就是Tab键

#注意:print 和 printf 的主要区别在有 printf 是标准的格式化输出,必须手动指定换行和tab.

在进行实验之前,首先创建一个文件,来做测试用

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log

ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

实例1: 通过 printf 函数打印文本内容

printf命令,如果不指定输出格式,则会把所有输出内容连在一起输出,其实文本的输出本身就是这样的,cat等文本输出命令之所以可以按照格式漂亮的输出,那是因为cat命令已经设定了输出格式.

代码语言:javascript
复制
[root@localhost ~]# printf '%s' $(cat lyshark.log)

IDNAMEAGEGenderMark1WR22m1002LC26m903LY23m884XDL40b100

实例2: 通过 printf 格式化后输出一段文本

代码语言:javascript
复制
[root@localhost ~]# printf '%s\t %s\t %s\t %s\t %s\t \n' $(cat lyshark.log)

ID       NAME    AGE     Gender  Mark
1        WR      22      m       100
2        LC      26      m       90
3        LY      23      m       88
4        XDL     40      b       100

实例3: 通过 printf 按照整数型和浮点型输出,则需要修改

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# printf '%i\t %s\t %8.2f\t %s\t %s\t \n' $(cat lyshark.log |grep -v ID)
1        WR         22.00        m       100
2        LC         26.00        m       90
3        LY         23.00        m       88
4        XDL        40.00        b       100

Awk 正则表达工具

awk是一种编程语言,用于在linux/unix下对文本和数据进行处理,数据可以来自标准输入(stdin),一个或多个文件,或其它命令的输出.它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具,它在命令行中使用,但更多是作为脚本来使用.awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势.

在开始看例子之前,老样子,你懂的

代码语言:javascript
复制
[root@localhost ~]# awk --help
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...

命令语法:[ awk '条件1{动作1} 条件2{动作2} ....' 文件名 ]

条件:一般使用关系表达式作为条件
                x>10    判断x变量是否大于10
                x==y    判断变量x是否等于变量y
                A ~ B   判断字符串A中是否包含能匹配B表达式的字符串
                A!~ B   判断字符串A中是否不包含能匹配B表达式的字符串

在进行实验之前,首先创建一个文件,来做测试用

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log

ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

◆awk常用例子◆

实例1: 使用awk格式化输出第二列和第三列的内容

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# awk '{ printf $2 "\t" $3 "\n" }' lyshark.log
NAME    AGE
WR      22
LC      26
LY      23
XDL     40

实例2: 通过awk命令截取Size和Used命令的显示列

代码语言:javascript
复制
[root@localhost ~]# df -h
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root  8.0G  1.2G  6.9G  15% /
devtmpfs                  98M     0   98M   0% /dev
tmpfs                    110M     0  110M   0% /dev/shm
tmpfs                    110M  5.5M  104M   5% /run
tmpfs                    110M     0  110M   0% /sys/fs/cgroup
/dev/sda1               1014M  130M  885M  13% /boot
tmpfs                     22M     0   22M   0% /run/user/0

[root@localhost ~]# df -h |awk '{ printf $2 "\t" $3 "\n" }'
Size    Used
8.0G    1.2G
98M     0
110M    0
110M    5.5M
110M    0
1014M   130M
22M     0

◆begin 与 end◆

BEGIN是awk的保留字,是一种特殊的条件类型.BEGIN的执行时机是 "在awk程序一开始时,尚未读取任何数据之前执行",一旦BEGIN后的动作执行一次,当awk开始从文件中读入数据,BEGIN的条件就不再成立,所以BEGIN定义的动作只能被执行一次,例如:

下面的,整个动作定义了两个动作,先打印 "执行语句前,执行我" 然后输出过滤后的2和4列

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# awk 'BEGIN{ printf "执行语句前,执行我 \n" }{ printf $2 "\t" $4 "\n" }' lyshark.log
执行语句前,执行我
NAME    Gender
WR      m
LC      m
LY      m
XDL     b

END也是awk保留字,不过刚好和BEGIN相反,END是在awk程序处理完所有数据,即将结束时执行.END后的动作只在程序结束时执行一次.

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# awk 'END{ printf "执行语句结束后,执行我 \n" }{ printf $2 "\t" $4 "\n" }' lyshark.log
NAME    Gender
WR      m
LC      m
LY      m
XDL     b
执行语句结束后,执行我

BEGIN与END连用,以下例子也就是实现了,开始前执行打印 "执行语句前,先执行我",结束时执行打印 "执行语句后,在执行我"

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# awk 'BEGIN{ printf "执行语句前,先执行我 \n" }END{ printf "执行语句后,在执行我 \n"}{ printf $2 "\t"
$4 "\n" }' lyshark.log

执行语句前,先执行我
NAME    Gender
WR      m
LC      m
LY      m
XDL     b
执行语句后,在执行我

◆awk关系运算◆

关系运算符:设定条件,符合执行不符合不执行,下面设定条件为AGE字段>=25岁的列出

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# cat lyshark.log | grep -v ID | awk '$3 >=25 {print $1 "\t" $2}'
2       LC
4       XDL

◆awk正则搜索◆

awk是列提取命令,第一步的动作却是先读入第一行,整个执行步骤: ⦁ 如果有BEGIN条件,则先执行BEGIN定义动作. ⦁ 如果没有BEGIN条件,则先读入第一行,把第一行的数据依次赋成0 1 2 3 …等变量,0 代表整行数据,1 则为第一个字段,依次类推. ⦁ 读入下一行,重复赋值变量,并打印数据.

指定搜索: 正则搜索第2列NAME字段,包含XDL的行,并打印出AGE列对应的值

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# awk '$2 ~/XDL/ {printf $3 "\n"}' lyshark.log
40

[root@localhost ~]# df -h
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root  8.0G  1.2G  6.9G  15% /
devtmpfs                  98M     0   98M   0% /dev
tmpfs                    110M     0  110M   0% /dev/shm
tmpfs                    110M  5.5M  104M   5% /run
tmpfs                    110M     0  110M   0% /sys/fs/cgroup
/dev/sda1               1014M  130M  885M  13% /boot
tmpfs                     22M     0   22M   0% /run/user/0

[root@localhost ~]# df -h | grep -v "Filesystem" | awk ' $1 ~/sda1/ {print $2}'
1014M

全局搜索: 正则全局搜索包含WR的字段行,并打印本行

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     Gender  Mark
1       WR      22      m       100
2       LC      26      m       90
3       LY      23      m       88
4       XDL     40      b       100

[root@localhost ~]# cat lyshark.log | awk '/WR/ {printf $0 "\n"}'
1       WR      22      m       100

屏蔽显示: 查看 df 的真实分区的使用情况,不看光盘和虚拟磁盘

代码语言:javascript
复制
[root@localhost ~]# df -h
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root  8.0G  1.2G  6.9G  15% /
devtmpfs                  98M     0   98M   0% /dev
tmpfs                    110M     0  110M   0% /dev/shm
tmpfs                    110M  5.5M  104M   5% /run
tmpfs                    110M     0  110M   0% /sys/fs/cgroup
/dev/sda1               1014M  130M  885M  13% /boot
tmpfs                     22M     0   22M   0% /run/user/0

[root@localhost ~]# df -h | awk '/sda[0-9]/ {printf $1 "\t" $5"\n"}'
/dev/sda1       13%

◆awk内置变量◆

实例1: 通过内置变量 FS=":" 定义分隔符,打印/etc/passwd文件的第1列和第3列

代码语言:javascript
复制
[root@localhost ~]# cat /etc/passwd |grep "/bin/bash"
root:x:0:0:root:/root:/bin/bash

[root@localhost ~]# cat /etc/passwd |grep "/bin/bash" | \
> awk 'BEGIN {FS=":"} {printf $1 "\t" $3 "\n"}'

root    0

实例2: 打印行内容的同时,打印出行号(NR变量),和字段数(NF变量)

代码语言:javascript
复制
[root@localhost ~]# cat /etc/passwd | grep "/bin/bash" | 
\ awk 'BEGIN{FS=":"} {print $1 "\t" $3 "\t" "行号: " NR "\t" "
字段数: " NF}'

root    0       行号: 1 字段数: 7

实例3: 打印行内容,首先判断 $1==sshd 然后再打印本行的行号等信息

代码语言:javascript
复制
[root@localhost ~]# cat /etc/passwd | grep "/sbin/nologin" | 
\ awk 'BEGIN{FS=":"}$1=="sshd" {print $1 "\t" $3 "\t" "行号
: " NR "\t" "字段数: " NF}'

sshd    74      行号: 13        字段数: 7

实例4: 一个分区统计的小例子

代码语言:javascript
复制
[root@localhost ~]# df -h |grep -v "Filesystem" | \
awk '$1=="/dev/sda1" {print $1 "\t" $5 "\t" "行号:" NR "\t" "字段数:" NF }'

/dev/sda1       13%     行号:6  字段数:6

◆awk流程控制◆

在awk编程中,因为命令语句非常长,输入格式时需要注意以下内容: ⦁ 多个条件{动作}可以用空格分割,也可以用回车分割. ⦁ 在一个动作中,如果需要执行多个命令,需要用";"分割,或用回车分割. ⦁ 在awk中,变量的赋值与调用都不需要加入"$"符. ⦁ 条件中判断两个值是否相同,请使用"==",以便和变量赋值进行区分.

实例1: 将第2行,到第4行,的内容加起来,最后输出结果

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     SEX     LINUX
1       LY      18      boy     100
2       SC      30      man     150
3       WR      22      man     90
4       ZSX     55      boy     96

[root@localhost ~]# awk 'NR==2{x=$3} NR==3{y=$3} NR==4{z=$3} {totle=x+y+z;print "Totle is:" totle}' lyshark.log
Totle is:0
Totle is:18
Totle is:48
Totle is:70
Totle is:70

[root@localhost ~]# awk 'NR==2{x=$3} NR==3{y=$3} NR==4{z=$3;totle=x+y+z;print "Totle is:" totle}' lyshark.log
Totle is:70

实例2: 统计AGE列,将年龄小于25岁的任过滤出来,并显示 is young man!

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     SEX     LINUX
1       LY      18      boy     10
2       SC      30      man     50
3       WR      22      man     90
4       ZSX     55      boy     96

[root@localhost ~]# cat lyshark.log | awk '{if (NR >= 2){if ($3 < 25) printf $2 " IS Young Man! \n"}}'
LY IS Young Man!
WR IS Young Man!

实例3: 统计LINUX列,当出现大于80分的,打印到屏幕上 is good man!

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     SEX     LINUX
1       LY      18      boy     10
2       SC      30      man     50
3       WR      22      man     90
4       ZSX     55      boy     96

[root@localhost ~]# cat lyshark.log | awk 'NR>=2 {temp=$5} temp>80 {printf $2 "IS Good Man!\n"}'
WRIS Good Man!
ZSXIS Good Man!

◆awk函数编写◆

实例1: 通过定义的函数格式,去匹配并传递参数

代码语言:javascript
复制
[root@localhost ~]# cat lyshark.log
ID      NAME    AGE     SEX     LINUX
1       LY      18      boy     10
2       SC      30      man     50
3       WR      22      man     90
4       ZSX     55      boy     96

[root@localhost ~]# cat lyshark.log | awk 'function lyshark(x,y) {printf x "\t" y "\n"}{lyshark($2,$5)}'
NAME    LINUX
LY      10
SC      50
WR      90
ZSX     96

实例2: awk中调用脚本,对于小的单行程序来说,将脚本作为命令行自变量传递给awk是非常简单的,而对于多行程序就比较难处理.当程序是多行的时候,使用外部脚本是很适合的.首先在外部文件中写好脚本,然后可以使用awk的-f选项,使其读入脚本并且执.

代码语言:javascript
复制
[root@localhost ~]# cat passwd.awk
BEGIN {FS=":"}
{print $1 "\t" $3}

[root@localhost ~]# cat /etc/passwd | awk -f passwd.awk
root    0
bin     1
daemon  2
adm     3
lp      4
sync    5
shutdown        6
halt    7
mail    8
operator        11
games   12
ftp     14
nobody  99
systemd-network 192
dbus    81
polkitd 999
sshd    74
postfix 89
chrony  998

diff/patch 文件比对

什么时候会用到文件的比对啊? 通常是『同一个套装软件的不同版本之间,比较配置文件的差异』,很多时候所谓的文件比对,通常是用在 ASCII 纯文字档的比对上的,那么比对文件最常见的就是 diff .

diff命令在最简单的情况下,比较给定的两个文件的不同.如果使用 "-" 代替 "文件" 参数,则要比较的内容将来自标准输入,diff命令是以逐行的方式,比较文本文件的异同处,如果该命令指定进行目录的比较,则将会比较该目录中具有相同文件名的文件,而不会对其子目录文件进行任何比较操作.

◆diff 生成补丁文件◆

代码语言:javascript
复制
[root@localhost ~]# diff --help
Usage: diff [OPTION]... FILES
Compare FILES line by line.

语法格式:[ diff [选项] 源文件 新文件 > *.patch ]

        -a          #将任何文档当做文本文档处理
        -b          #忽略空格造成的不同
        -B          #忽略空白行造成的不同
        -I          #忽略大小写造成的不同
        -N          #当比较目录时,若某个文件只在一个目录中,则另一个目录中视作空文件
        -r          #当比较目录时,递归比较子目录
        -u          #使用同一的输出格式

-----------------------------------------------------------------
说明: 生成补丁的例子

1.首先创建两个文件,分别写入以下内容,内容要不同,因为要生成补丁.

[root@localhost ~]# cat old
hello world

[root@localhost ~]# cat new
hello world

welcome to lyshark blog

2.利用命令生成补丁文件 *.patch

[root@localhost ~]# diff -Naur /root/old /root/new > lyshark.patch

[root@localhost ~]# cat lyshark.patch
--- /root/old   2018-09-21 05:41:55.487052312 -0400
+++ /root/new   2018-09-21 05:42:10.581184526 -0400
@@ -1 +1,3 @@
 hello world
+
+welcome to lyshark blog

#最后,生成的lyshark.patch就是补丁文件了,我们可以使用下面的命令对old文件打补丁了.

◆patch 文本打入补丁◆

patch命令被用于为开放源代码软件安装补丁程序,让用户利用设置修补文件的方式,修改更新原始文件.如果一次仅修改一个文件,可直接在命令列中下达指令依序执行,如果配合修补文件的方式则能一次修补大批文件,这也是Linux系统核心的升级方法之一.

注意:精简模式下没有这个命令,需要执行 yum install -y patch 安装一下

代码语言:javascript
复制
[root@localhost ~]# patch --help
Usage: patch [OPTION]... [ORIGFILE [PATCHFILE]]

语法格式:[ patch [-pn] 旧文件 < *.patch ]

        -p:设置要剥离的目录层数   
        n:代表补丁文件中记录的文件old所在目录层数,用于更新old文件时匹配正确路径

-----------------------------------------------------------------
说明: 给old文件打补丁

[root@localhost ~]# ls
lyshark.patch  new  old

[root@localhost ~]# patch -p2 old < lyshark.patch
patching file old

[root@localhost ~]# cat old
hello world

welcome to lyshark blog

[root@localhost ~]# cat new
hello world

welcome to lyshark blog
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-01-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基础正则表达式
  • 扩展正则表达式
  • Grep 行处理工具
  • Cut 列提取工具
  • Sed 流编辑器
  • Printf 文本格式化
  • Awk 正则表达工具
    • ◆awk常用例子◆
      • ◆begin 与 end◆
        • ◆awk关系运算◆
          • ◆awk正则搜索◆
            • ◆awk内置变量◆
              • ◆awk流程控制◆
                • ◆awk函数编写◆
                • diff/patch 文件比对
                  • ◆diff 生成补丁文件◆
                    • ◆patch 文本打入补丁◆
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档