linux文本处理三剑客

awk、grep、sed是linux操作文本的三大利器,合称文本三剑客,也是必须掌握的linux命令之一。三者的功能都是处理文本,但侧重点各不相同,其中属awk功能最强大,但也最复杂。

grep更适合单纯的查找或匹配文本,sed更适合编辑匹配到的文本,awk更适合格式化文本,对文本进行较复杂格式处理。

grep

什么是grep和egrep

Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来(匹配到的标红)。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。

  grep的工作方式是这样的,它在一个或多个文件中搜索字符串模板。如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名。搜索的结果被送到标准输出,不影响原文件内容。

  grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态,如果模板搜索成功,则返回0,如果搜索不成功,则返回1,如果搜索的文件不存在,则返回2。我们利用这些返回值就可进行一些自动化的文本处理工作。

  egrep = grep -E:扩展的正则表达式 (除了< , > , \b 使用其他正则都可以去掉\)

正则推荐学习网站:https://regexlearn.com/zh-cn

使用grep

grep命令格式

1
grep [option] pattern file

命令参数

  • -A<显示行数>:除了显示符合范本样式的那一列之外,并显示该行之后的内容。
  • -B<显示行数>:除了显示符合样式的那一行之外,并显示该行之前的内容。
  • -C<显示行数>:除了显示符合样式的那一行之外,并显示该行之前后的内容。
  • -c:统计匹配的行数
  • -e :实现多个选项间的逻辑or 关系
  • -E:扩展的正则表达式
  • -f FILE:从FILE获取PATTERN匹配
  • -F :相当于fgrep
  • -i –ignore-case #忽略字符大小写的差别。
  • -n:显示匹配的行号
  • -o:仅显示匹配到的字符串
  • -q: 静默模式,不输出任何信息
  • -s:不显示错误信息。
  • -v:显示不被pattern 匹配到的行,相当于[^] 反向匹配
  • -w :匹配 整个单词

实例

1
2
3
4
5
6
# 准备一个测试文件
aaaaa
bbbbbb
ccccCCC
ddDDDdd
ABCD

image-20220929133234367

1
2
# 显示匹配到的b的那一行,并显示后面2行
grep -A2 b test.txt

image-20220929133423071

1
2
# 显示匹配到b的那一行,并显示之前1行
grep -B1 b test.txt

image-20220929133647430

1
2
# 显示匹配到b的那一行,并显示前后1行
grep -C1 b test.txt

image-20220929133752685

1
2
# 统计匹配到的行数
grep -c D test.txt

image-20220929133953358

1
2
# 实现多个选项间的逻辑or关系
grep -e a -e c test.txt

image-20220929134436988

1
2
# 从FILE获取PATTERN匹配
grep -f pattern test.txt

image-20220929135042896

1
2
#  -i --ignore-case #忽略字符大小写的差别
grep -i d test.txt

image-20220929135222339

1
2
# -n:显示匹配的行号
grep -n D test.txt

image-20220929135316963

1
2
# -o:仅显示匹配到的字符串
grep -o Dd test.txt

image-20220929135440679

1
2
# -v:显示不被pattern 匹配到的行,相当于[^] 反向匹配
grep -v d test.txt

image-20220929135610559

1
2
# -w :匹配 整个单词
grep -w ABCD test.txt

image-20220929135720976

补充

一般我们使用grep都是配合管道符号 |使用的 比如查看nginx进程,

1
2
# 查看nginx进程,判断nginx是否开启
ps -aux | grep nginx

image-20220929142145897

1
2
# 查看80端口是否被占用
netstat -tunlp | grep 80

image-20220929142306852

sed

什么是sed

sed 是一种流编辑器,它一次处理一内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(patternspace ),接着用sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。然后读入下行,执行下一个循环。如果没有使诸如‘D’ 的特殊命令,那会在两个循环之间清空模式空间,但不会清空保留空间。这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出或-i

20200622105532480

  功能:主要用来自动编辑一个或多个文件, 简化对文件的反复操作

sed的使用

命令格式

1
sed  [options]  '/pattern/ command'  file(s)

常用选项options

  • -n:不输出模式空间内容到屏幕,即不自动打印,只打印匹配到的行
  • -e:多点编辑,对每行处理时,可以有多个Script
  • -f:把Script写到文件当中,在执行sed时-f 指定文件路径,如果是多个Script,换行写
  • -r:支持扩展的正则表达式
  • -i:直接将处理的结果写入文件
  • -i.bak:在将处理的结果写入文件之前备份一份

编辑命令command

  • d:删除模式空间匹配的行,并立即启用下一轮循环
  • p:打印当前模式空间内容,追加到默认输出之后
  • a:在指定行后面追加文本,支持使用\n实现多行追加
  • i:在行前面插入文本,支持使用\n实现多行追加
  • c替换行为单行或多行文本,支持使用\n实现多行追加
  • w:保存模式匹配的行至指定文件
  • r:读取指定文件的文本至模式空间中匹配到的行后
  • =:为模式空间中的行打印行号
  • !:模式空间中匹配行取反处理
  • s///:查找替换,支持使用其它分隔符,如:s@@@,s###;
    • 加g表示行内全局替换;
    • 在替换时,可以加一下命令,实现大小写转换
    • \l:把下个字符转换成小写。
    • \L:把replacement字母转换成小写,直到\U或\E出现。
    • \u:把下个字符转换成大写。
    • \U:把replacement字母转换成大写,直到\L或\E出现。
    • \E:停止以\L或\U开始的大小写转换

sed实例

1
2
# 还是那个测试文件
cat test.txt

image-20220929151337242

1
#  p:匹配到的行会打印一遍,不匹配的行也会打印

image-20220929153425829

1
# -n:不输出模式空间内容到屏幕,即不自动打印,只打印匹配到的行

image-20220929154541975

1
2
# -e:多点编辑,对每行处理时,可以有多个Script
sed -n -e '/D/p' -e '/a/p' test.txt

image-20220929155453651

1
# -f:把Script写到文件当中,在执行sed时-f 指定文件路径,如果是多个Script,换行写

image-20220929155703145

1
2
# a:在指定行后面追加文本,支持使用\n实现多行追加
sed '2a 111' test.txt #在第二行后面加上111

image-20220929160545221

1
2
#  i:在行前面插入文本,支持使用\n实现多行追加
sed '2i 111' test.txt # 在第二行前面加上111

image-20220929160951595

1
2
#  c:替换行为单行或多行文本,支持使用\n实现多行追加
sed '2c 111\n222' test.txt # 替换第二行 \n 再添加一行

image-20220929161329686

1
2
# w:保存模式匹配的行至指定文件
sed '/bbb/w 1.txt' test.txt # 将匹配到的写入1.txt

image-20220929162354187

1
2
# r:读取指定文件的文本至模式空间中匹配到的行后
sed '3 r 1.txt' test.txt # 将1.txt中的内容读取并追加到test第三行后面

image-20220929162834407

1
2
#  =:为模式空间中的行打印行号
sed '=' test.txt

image-20220929164239888

1
2
#  !:模式空间中匹配行取反处理
sed -n '/aaa/!p' test.txt

image-20220929164759315

1
2
# s///:查找替换,支持使用其它分隔符,如:s@@@,s###;
sed 's/bbb/111/' test.txt # 将bbb替换为111

image-20220929165839261

1
2
# 加g表示行内全局替换;
sed 's/bbb/111/g' test.txt

image-20220929165939258

awk

什么是awk

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

  awk其实不仅仅是工具软件,还是一种编程语言。不过,本文只介绍它的命令行用法,对于大多数场合,应该足够用了。

awk的使用

命令格式

1
2
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)

常用命令选项

  • -F fs fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:
  • -v var=value 赋值一个用户定义变量,将外部变量传递给awk
  • -f scripfile 从脚本文件中读取awk命令

语法结构

awk是由patternaction组成, pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令.

1
awk '{pattern + action}' {filenames}

pattern 可以是如下几种或者什么都没有(全部匹配):

  • /正则表达式/:使用通配符的扩展集。
  • 关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试。
  • 模式匹配表达式:用运算符(匹配)和!(不匹配)。
  • BEGIN语句块、pattern语句块、END语句块:参见awk的工作原理

action 由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内,可以是如下几种,或者什么都没有(print)

  • 变量或数组赋值
  • 输出命令
  • 内置函数
  • 控制流语句

awk常见应用和工作原理

下面列出一个最常用的awk命令结构,借此分析原理

1
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
  • 首先执行 BEGIN {commands} 内的语句块,注意这只会执行一次,经常用于变量初始化,头行打印一些表头信息,只会执行一次,在通过stdin读入数据前就被执行;
  • 从文件内容中读取一行,注意awk是以行为单位处理的,每读取一行使用 pattern{commands} 循环处理 可以理解成一个for循环,这也是最重要的部分;
  • 最后执行 END{ commands } ,也是执行一次,在所有行处理完后执行,一帮用于打印一些统计结果。

实例:

1
2
3
4
5
6
cat -n /etc/passwd | awk -F ':' 'BEGIN {print "start"} { print  $1,$2} END {print "end"}'
# -F ':' 以逗号为分隔符 默认为空格
# BEGIN 执行打印start 且只打印一次
# 正常执行
# print $1,$2 打印第一列,第二列
# END 执行end 且只打印一次

image-20221008162809171

awk的内置变量

  • FS输入字段分隔符默认为空白字符
1
head -n 5 passwd.bak | awk -v FS=':' '{print $1,$2}'

image-20221009085738131

  • OFS输出字段分隔符,默认为空白字符
1
head -n 5 passwd.bak | awk -v FS=':' -v OFS='----' '{print $1,$2}'

image-20221009085858108

  • RS :输入记录分隔符,指定输入时的换行符,原换行符仍有效,原来是以\n 作为行分隔符
1
2
# 查看测试文件
cat RStest.txt

image-20221009090939008

1
2
# 以空格为行分隔符
awk -v RS=' ' '{print }' RStest.txt

image-20221009090958640

1
2
# 以段落为分隔符
awk -v RS='' '{print }' RStest.txt

image-20221009091226879

  • ORS :输出记录分隔符,输出时用指定符号代替换行符
1
2
# 输出的时候不再用原来的`\n` 而是改成指定的
awk -v ORS='====' '{print $1 }' RStest.txt

image-20221009091833721

  • NF :字段数量,共有多少字段, $NF引用最后一列,$(NF-1)引用倒数第2列
1
2
# NF显示字段数量
awk '{print $0,NF}' RStest.txt

image-20221009092203782

1
2
# $NF引用最后一列
awk '{print $NF}' RStest.txt

image-20221009092301063

  • NR行号,后可跟多个文件,第二个文件行号继续从第一个文件最后行号开始
1
2
# 显示行号
awk '{print NR, $0}' RStest.txt

image-20221009092415427

  • FNR :各文件分别计数, 行号,后跟一个文件和NR一样,跟多个文件,第二个文件行号从1开始 单个文件与NR没区别
1
awk '{print FNR,$0}' RStest.txt

image-20221009093022957

1
awk '{print FNR,$0}' RStest.txt RStest.txt

image-20221009093044682

  • FILENAME :当前文件名
1
awk '{print FILENAME,$0}' RStest.txt

image-20221009093824115

  • ARGC :命令行参数的个数

  • ARGV :数组,保存的是命令行所给定的各参数,查看参数

自定义变量

1
2
# 用-v 自义定变量
awk -v name='123' '{print name}' RStest.txt

image-20221009094432611

常用实例

1
2
3
# 在 a b c d  的b 后面插入新字段 e f g
# 将$2 重新赋值,再打印,两个命令用分号隔开
echo 'a b c d ' | awk '{$2=$2" e f g";print}'

image-20221009100423723

1
2
# 从ifconfig命令的结果中筛选出除了lo网卡外的所有IPV4地址.
ifconfig | awk '/inet /&&$2!~/127/ {print $2}'

image-20221009110955242

1
2
# 读取配置文件中的某一段配置
# 比如说我们要读取yum配置文件中的中间一段

image-20221009111429559

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
vim 1.awk

# 匹配centosplus,[] 需要用转义符号\
/\[centosplus\]/{
# 打印
print
# 获取每一行
# getline > 0 表示有数据
# getline = 0 表示遇到结尾
# getline < 0 表示有错误
while ((getline var)>0){
# 当var 遇到下一个[] 退出
if (var~/\[.*\]/){
exit
}
# 打印var
print var
}
}

1
awk -f 1.awk /etc/yum.repos.d/CentOS-Base.repo

image-20221009154416803

1
2
3
4
5
6
7
8
9
10
11
# 去重
cat 1.txt
aa
aa
aa
bb
bb
cc
cc
# 用数组arr 将$1存起来,arr[$1]次数+1,然后判断arr[$1]是不是第一次出现,如果是第一次就打印
awk '{arr[$1]=arr[$1]+1;if(arr[$1]==1){print}}' 1.txt

image-20221009141427509

1
2
3
4
5
6
# 统计数量
# 用数组将出现的arr[$1]存起来,
# 打印
awk '{arr[$1]=arr[$1]+1}END{for (i in arr){print arr[i],i}}' 1.txt
# 更简单
cat 1.txt | uniq -c
1
2
3
4
5
6
7
8
9
# 取字段中的指定字段数量
cat 2.txt
1 001dfad
2 003asda
3 00412312
4 006123asda

# 用substr获取子串
awk '{print $1,substr($2,1,3)}' 2.txt

image-20221010144225925