前言
经常会用到相关的文本处理命令来查询信息,有些语法太久没用就忘了经常需要去查资料,于是就想整理一篇文章出来方便自己查看,也希望对各位读者有所帮助。
一、cut命令
cut命令是一个相对比较简单的命令,主要用来做文本的切割,和之前介绍过的split
命令不同,cut命令是根据文本内容来做切割的,而不是根据文件大小来进行切割的。
参数 | 作用 |
---|---|
-f | 指定要哪一列的数据,多列数据则用逗号隔开,相连的列可以用中横线表示比如3-5
|
-d | 指定分隔符,默认情况下cut命令用制表符来进行分隔 |
-n | 显示行号 |
我们给一个测试文件,一共有三列数据,我们希望把第1列和第3列的数据提取出来放到一个新的文件里面
Jack Boy 19
Marry Girl 15
John Boy 45
Amy Girl 30
通过观察我们可以发现文件是以空格来进行文本分隔的,我们可以通过cut -d " " -f 1,3 cut_test > cut_result.log
这个命令来实现
最后输出结果如下
注意事项:cut虽然简单易用,但除了比较简单的场景外我们用的比较少,原因就是cut只支持单个字符作为分隔符,对于多字符或者不规则字符分隔的列就很不好用了。比如ps -ef
的结果集
二、awk命令
awk
是比cut
命令更加强大的文本处理工具,不仅体现在文本分割更加灵活,awk
还有着强大的文本处理能力。
awk [选项] ‘[BEGIN] 模式或条件 {操作} [END]’ 文件1 文件2...
(一)常用选项
选项 | 作用 |
---|---|
-F | 指定分隔符,默认为空白字符 |
-v var=value | 再程序开始前设置变量 |
(二)内置变量
变量名 | 作用 |
---|---|
$0 | 当前处理行整行的内容 |
$n | 当前处理行的第n列 |
NR | 当前处理行的行号 |
NF | 当前处理行的字段数 |
FS | 输入字段分隔符(默认为空白字符) |
OFS | 输出字段分隔符(默认为空白字符) |
FILENAME | 当前被处理的文件名 |
RS | 输出记录分隔符(默认为换行符) |
(三)工作原理
- BEGIN 语句块:在处理任何输入行之前执行,主要用于初始化操作
- 处理输入行:对于每一行输入,awk 会检查是否匹配指定的模式或条件,如果匹配,则执行相应的操作。
- END 语句块:在处理完所有输入行之后执行,常用于汇总或输出最终结果。
(四)案例演示
1. 获取现在所有java进程对应的启动用户和进程号
cut
命令做不到的切分到这里就顺利实现了!
ps -ef | grep java | awk '{print $1 " " $2}'
2、指定分隔符进行切分
有如下文本,文本内容通过aba
进行分隔的,我们现在按照aba
作为分隔符进行分隔,取第1,2列
JackabaBoyaba19
MarryabaGirlaba15
JohnabaBoyaba45
AmyabaGirlaba30
对应的脚本内容如下:
awk -F 'aba' '{print $1 " " $2}' awk_test
3、打印文本指定行数
我们希望分别打印文件中第1,3行和第2-4行到新的文件中,这里节省一下空间我们就还是沿用cut
中的案例
- 打印文本中的第1行和第3行
awk 'NR==1 || NR==3 {print $0}' awk_test
- 打印文本中的第2-4行
下面2种语法都可以实现
awk 'NR==1, NR==3 {print $0}' awk_test
awk '(NR>=1)&&(NR<=3) {print $0}' awk_test
4、在输出结果中的前面加入行号打印
这里其实可以结合cut
、cat
命令来辅助我们做新的行号,不过为了方便演示awk
的语法,我们就还是用awk
来实现
awk '{print NR " " $0}' awk_test
5、加入标题和结尾
我们可以使用BEGIN
和END
来在所有文本处理前后加一下打印语句,比较多的话是加一下标题,然后在结束的地方加一下结束语或者是做一下统计。我们这里就简单写一个用例吧,在处理前后打印一下开始和结束的关键字
awk 'BEGIN {print "===START EXECUTE==="} {print $0} END {print "===END==="}' awk_test
6、根据关键词or正则进行过滤
awk
在文本过滤上面也是一把好手,我们可以使用/regex/{print}
的方式来实现文本过滤,比如说我们希望把性别为女的数据给筛选出来,可以有几种方式来实现
- 直接通过关键字进行匹配
awk '/Girl/{print $0}' awk_test
- 通过条件判断来实现
awk '$2=="Girl" {print}' awk_test
7、利用BEGIN
和END
来做统计
我们知道BEGIN
和END
可以分别在文本处理前后做一些事情,那么我们可以利用这个特点来做一下数据的统计
比如说下面的文件有商品名和价格
IPhone 3000
T-Shirt 50
Bag 20
Coke 15
我们希望统计出文件的总行数和所有商品的价格,可以借助BEGIN
来设置变量,中间过程来计算变量,END
展示结果值
awk 'BEGIN {tP=0;tR=0} {print $0;tR++;tP+=$2} END {print "total Price is " tP " totalRowNum is " tR}' awk_test2
(五)进阶用法
1. 利用akw
命令实现分组
awk
的功能十分强大,我们甚至可以结合数组来进行数据的分组统计,我们可以看下面这个文件
新华字典 30
我与地坛 15
母猪的产后处理 10
我与地坛 15
新华字典 30
新华字典 30
我们希望统计文件中每种书籍出现的次数,格式为书名 出现次数
,并且按出现的次数从高到低进行展示。可以使用下面的命令来实现
awk '{count[$1]++;} END {for(i in count) {print i " " count[i]}}' awk_test3 | sort -rn -k 2
我们简单解释一下这条命令吧
-
count[$1]++
创建一个关联数组 count,以每行的第1个字段的值为键,并将该键的值增加 1。如果键不存在,它会自动创建并初始化为 0,然后执行增加操作。 -
END {for(i in count) {print i count[i]}}
for(i in count)
遍历 count 数组中的所有键。print i " " count[i]
:打印每个键及其对应的计数,为了展示和方便计算,我们这里顺便加了一个空格 -
sort -rn -k 2
这里是用sort命令取第二列作为排序列,-r
进行倒序排序,-n
指定按数字大小进行排序
这里有读者可能会困惑,数组的索引值一般不是数字吗?这里怎么保证分组的字段名刚好是数字呢?这个困惑我也有过,后面查询资料后发现在awk
中数组的键(key)可以是数字、字符串或者是表达式的结果,不一定非得是数字。实际上,awk 数组更像是哈希表(hash table),而不是传统意义上的数组,因为它们不是基于索引的,而是基于键值对的。
三、sed命令
待补充...
四、grep命令
待补充...
小结
总体来说,cut
适合简单场景的文本切割,复杂的文本不建议使用。grep
更适合查日志、在文本中查关键字的时候使用。对于提取数据或者批量编辑数据,sed
和awk
则更好用,当然学习成本也更高一些,个人感觉sed
更适合编辑匹配到的文本,awk
可以配合来做文本切割、文本处理、筛选、统计等这类格式化的操作。