Linux三剑客:高效的数据分析

1.Linux三剑客是什么

首先,我们想了解Linux三剑客具体是什么?

  1. 第一个工具是grep,grep在每个文件中或匹配的每一行进行pattern模式,即根据正则表达式搜索内容并打印出来
  2. 第二个工具是awk,awk由三个作者名字缩写(Aho, Kernighan, Weinberger),它可以根据定位到的数据行处理其中的分段。
  3. 第三个工具是sed,它是stream editor编辑器简介,根据输入内容作出过滤的文本能力,对过滤数据进行增删改查操作。

它们三个组合来使用,可以应对Shell中的很多数据分析场景,所以人们都把这三个工具统称为Linux三剑客。

2.Linux三剑客有什么用

接下来,通过对三剑客与SQL进行类比,来具体看看它们到底能做什么?

  1. grep相当于SQL的select * from table,它可以进行数据的查找与定位。
  2. awk相当于SQL的select columns from table,它可以进行数据的切片。
  3. sed相当于SQL的select columns from table where columns=xxupdate table set columns=new where columns=old,它可以进行数据的条件查询或修改等

你可以发现,grep 和 awk 可以进行组合使用,来达到查找数据并对数据进行分割的目的,grep 也可以与 sed 组合使用,达到查找数据并修改的目的,它们三个还可以组合在一起使用来完成一系列的操作,就相当于大数据处理中的 Map-Reduce,我们接下来看如何具体的使用它们。

3.Linux三剑客具体怎么用

我们先创建一个文件,文件内包括三条数据,后文以该文件内容作为演示操作

#方式1: vim test.txt(在当前目录下新建一个文件,输入如下三条数据)
hello from hogwarts
hello from sevenriby
hello from testerhome
# 方式2:使用echo命令输入,其中-e参数表示开启转义符的解释功能
echo -e 'hello from hogwarts\nhello from sevenriby\nhello from te
sterhome' > test.txt

# -------------------------查看-------------------------
#rosaany@Rosefinch:~$ cat test.txt
#hello from hogwarts
#hello from sevenriby
#hello from testerhome

3.1 grep

grep用于根据正则表达式模式查找相关内容并打印对应数据。

  • 查找hogwarts单词是否在文件中
rosaany@Rosefinch:~$ grep hogwarts test.txt
hello from hogwarts
# 匹配到hogwarts单词,输出一整行
  • 查找以hello开头的单词是否在文件中
rosaany@Rosefinch:~$ grep '^he' test.txt
hello from hogwarts
hello from sevenriby
hello from testerhome
  • 查找包含i或y字母的单词是否在文件中
rosaany@Rosefinch:~$ grep '[iy]' test.txt
hello from sevenriby
  • 加入-v参数过滤掉匹配到的内容
rosaany@Rosefinch:~$ grep -v '[iy]' test.txt
hello from hogwarts
hello from testerhome
  • -o参数表示只打印匹配的数据
rosaany@Rosefinch:~$ grep -o '[iy]' test.txt
i
y
  • -E参数表示支持使用扩展正则表达式

grep这里的(pattern模式)正则表达式分为两类,第一类称为基本表达式,基本表达式包括了典型的正则标识符。

  1. ^表示开头;
  2. $表示结尾;
  3. []表示任意匹配项;
  4. *表示0个或多个;
  5. .表示任意字符

第二类是扩展表达式,它在基础表达式上做了一些扩展,支持更高级的语法和更复杂的条件。

  1. ?表示非贪婪匹配;
  2. +表示一个或多个;
  3. ()表示分组;
  4. {}表示一个范围的约束;
  5. |表示匹配多个表达式的任何一个
  • 加入-E参数,查找一个包括seven或home单词是否在文件中
rosaany@Rosefinch:~$ grep -E "(seven|home)" test.txt
hello from sevenriby
hello from testerhome
  • 不加入-E参数,查找一个包括seven或home单词是否在文件中
rosaany@Rosefinch:~$ grep  "\(seven\|home\)" test.txt
hello from sevenriby
hello from testerhome
# --------加入\转义符对匹配条件进行转移,也可以达到同样的效果。

3.2 awk

awk是一种语言解析引擎,它的功能非常强大,具备完整的编程特性,可以执行命令、进行网络请求等操作。

接下来看下 awk 的语法 awk 'pattern{action}' 的相关知识,pattern 是匹配条件,action 表示具体需要做的处理。

  • 使用双/表示一个正则匹配,效果如同前面的grep一样
rosaany@Rosefinch:~$ awk  "/(seven|home)/" test.txt
hello from sevenriby
hello from testerhome

pettern 语法在一定程度上可以代替 grep,但没有使用grep简洁

  • 查找第3行数据
rosaany@Rosefinch:~$ awk 'NR>=3' test.txt
hello from testerhome
# NR参数代表记录数

pattern有非常丰富的语法,你可以课后自己进行练习,同时 awk 还有几个标准的内置变量。

  1. FS 表示字段分隔符
  2. OFS 表示输出数据的字段分隔符
  3. RS 表示记录分隔符`
  4. ORS表示输出字段的行分隔符
  5. NF 表示字段数
  6. NR 表示记录数
  • 查找文件记录数与字段数
rosaany@Rosefinch:~$ awk '{print NR,NF}' test.txt
1 3
2 3
3 3
# 默认空格作为分隔符,分别输出第一行有3个字段,第二行有3个字段,第三个有3个字段
  • 查找文件记录数与字段数(指定分隔符o,使用-F参数指定)
rosaany@Rosefinch:~$ awk -Fo '{print NR,NF,$1,$2,$3,$4}' test.txt
1 4 hell  fr m h gwarts
2 3 hell  fr m sevenriby
3 4 hell  fr m testerh me
# $1~$n输出对应的记录
  • 也可以使用BEGIN指令分隔符
rosaany@Rosefinch:~$ awk  'BEGIN{FS="o"}{print NR,NF,$1,$2,$3,$4}' test.txt
1 4 hell  fr m h gwarts
2 3 hell  fr m sevenriby
3 4 hell  fr m testerh me
# FS变量指定分隔符
  • 输出数据指定字段分隔符|
rosaany@Rosefinch:~$ awk  'BEGIN{OFS="|"}{print NR,NF,$1,$2,$3,$4}'test.txt
1|3|hello|from|hogwarts|
2|3|hello|from|sevenriby|
3|3|hello|from|testerhome|
  • 输出数据指定字段分隔符|,OFS直接指定
rosaany@Rosefinch:~$ awk  'OFS="|"{print NR,NF,$1,$2,$3,$4}' test.txt
1|3|hello|from|hogwarts|
2|3|hello|from|sevenriby|
3|3|hello|from|testerhome|
  • awk还支持简单的运算功能
rosaany@Rosefinch:~$ awk 'BEGIN{print 10/3}'
3.33333

除了这些之外,awk 还支持词典,用来统计一些特征和数据,它类似于 Java 的 hash 和 Python 的字典。awk 的语法非常灵活,希望你在课后能够把文档打印出来仔细阅读,它可以帮助你在日后的数据分析工作中更加得心应手。

3.3 sed

sed的具体常用法如下:

  1. sed[addr]X[options],其中 [] 定义了一个范围,x位是具体操作,options表示进行数据修改的选项。
  2. -e 表示可以指定表达式。
  3. sed -n '2p' 2 表示打印第二行的数据
  4. s 表示查找并替换
  5. -i 表示直接修改源文件
  6. -E 支持扩展表达式。
  • 使用s查找前面的内容并替换为后面内容
rosaany@Rosefinch:~$ sed 's#test#testing#' test.txt
hello from hogwarts
hello from sevenriby
hello from testingerhome
# ‘#’或‘/’都可以表示分隔符
# testerhome 变为 testingerhome
  • 以t开头的三个字符替换成xxx
rosaany@Rosefinch:~$ sed 's/t../xxx/g' test.txt
hello from hogwarts
hello from sevenriby
hello from xxxxxxhome
# s/../../g表示全局替换
# testerhome 变为 xxxxxxhome

如果你想给定具体的行数或范围通过正则匹配作替换修改

rosaany@Rosefinch:~$ sed '3,$ s/t../xxx/g' test.txt # 直接指定范围($表示到最后一行)
hello from hogwarts
hello from sevenriby
hello from xxxxxxhome
  • 删除指定行
rosaany@Rosefinch:~$ sed '1 d' test.txt
hello from sevenriby
hello from testerhome

awk更专注于数据的提取,而sed更专注于数据的修改,sed的重要作用是完成对数据的增删改查工作,比如:

  1. d 是删除
  2. p 是打印
  3. s 是查找并进行替换
  4. \1 \2 可以根据匹配的数据进行分组处理

4. 管道组合

管道符|,在shell中表示将上一个指令的输出自动变成下一个指令的输入。

  • 给定具体的行数或范围通过正则匹配作替换修改
rosaany@Rosefinch:~$ awk 'NF<2' test.txt | sed 's/t../xxx/g'
rosaany@Rosefinch:~$ awk 'NF>2' test.txt | sed 's/t../xxx/g'
hello from hogwarts
hello from sevenriby
hello from xxxxxxhome
  • grep、awk、sed的结合
rosaany@Rosefinch:~$ cat test.txt | grep hogwarts | awk '{print $3}' | sed 's/h../xxx/g'
# -----------------输出-----------------
xxxwarts
# 输入cat命令指定输出文件,接着grep只保留hogwarts所在的行,接着awk打印处第三个字段,最后sed把h开头的三个字符替换为xxx。

通过管道我们很容易让Linux三剑客的功能发挥到一个新高度,有了管道很多的操作就变得非常的简单容易处理。通过管道于三剑客相结合使用可以实现非常好的效果,它可以帮助我们处理一些复杂的数据处理工作,提高我们的工作效率。

参考文章

部分引用:测试开发核心技术 46 讲 -- Linux三剑客,来自:拉勾教育
参考:man sed, man grep, man awk文档详解

上一篇:shell学习第七天之Linux三剑客grep,sed,awk


下一篇:shell基础---AWK+UNIQ+SORT 统计文件中某字符串出现次数并排序