【Linux】常用的文本操作(排序、选取、计数、应用正则表达式查找等)

来源:互联网 发布:mac终端是什么意思 编辑:程序博客网 时间:2024/06/12 22:03

最近面试(NLP类)经常被问到linux如何找出文本中的空行/含某个词的行这样的问题。第一次被问到时尴尬地回了句“能不能用python”,简直是黑历史。下面一次性总结一下相关知识:

一、pipe:

Linux很好用的功能,可以用来写个“加工线”(pipeline),每个步骤间用竖线“|”分隔,前一步骤的结果传入下一步骤,最后显示最终步骤得到的结果。即:步骤1|步骤2|……|步骤n,最后显示步骤n的结果。从某些功能(比如tee,类似“三通”,下面会介绍)可以看出当初pipe的设计思路就好像水管。

二、cut和grep:

cut和grep分别对应列操作和行操作。

cut能够对输入的每一行进行切分,每行只输出希望保留的某些列,有两个参数:

$ cut -d '分隔字符' -f [第几项]
$ cut -c '字符范围'
其中,-d用于被特定字符分隔的行,有点像python中的split('分隔字符')。后面跟的参数表示分隔后选取哪一项。

例子:

$ echo 'I love coding' | cut -d ' ' -f 2
就会首先将原句按照空格切分成3个项,然后输出第二项,也就是love。

-c参数表示需要保留的字符范围,从1开始。例子:

$ echo 'I love coding' | cut -c 3-5
lov
输出了第3-5个字符,lov。


grep是用来应对行操作的。针对多行的输入,grep能够搭配正则表达式,分析并输出希望得到的行,或排除某些行。正则表达式的内容足够新开一篇,这里就不赘述了,直接写几个例子:

1. 直接跟字符串:筛选出含这一段字符的行

$ echo -e 'I love coding\nI hate running' | grep 'hate'
I hate running
2. 用正则表达式,选出以'#'开头的:

$ echo -e 'I#love@coding\nI hate#running\n#I can sleep all day' | grep '^#'
#I can sleep all day
3. '-v':排除满足条件的,'-n':打印找到的行的行号,例子是”选出不以#开头的,并列出行号“:

$ echo -e 'I#love@coding\nI hate#running\n#I can sleep all day' | grep -vn '^#'

1:I#love@coding

2:I hate#running


三、sort,wc,uniq

嗯,顾名思义,这三个分别代表排序(sort),单词计数(word count),唯一值(unique)。pipe中读入多行后,可以用这些来进行进一步筛选。

sort有许多参数。单独使用sort会以字母表顺序升序排序。如果在排数字,会发现‘10’排在了‘2’的前面,因为第一个字符‘1’在‘2’的前面。搭配参数‘-n’表示遇到数字时按数字顺序排序。sort的参数'-u'可以在排序后输出时把重复项只显示一个,在后面加一个pipe用'uniq'也可以起同样效果。如果想要降序排序,可以用'-r’实现。

在排序时,比如输入是一个表,有时会想要按某一列排序(如果直接用sort会按整行来排)。这个时候就用到'-t‘和'-k'了。

说了一堆,用一个例子总结一下,假如输入是一行行的IP地址(长得像123.223.233.133这样),保存在IP_add文件中:

$ cat IP_add | sort -t '.' -k 2,3r -n -u
就能够输出:按IP地址第二个数升序排列,如果第二个数相同,按第三个数降序排列;排列时按数字顺序;重复的IP只输出一次。

wc不是“WC"哦。它能够数出输入的行数、单词数、字符数。搭配前面的grep可以轻易地取得一些大文本数据的统计数字。例如我被考到的”如何用linux统计10000行文本的空行数“,一行代码就可以解决:

$ cat 10000lines.txt | grep '^$' | wc -l
wc后的参数'-l'表示输出行数,如果需要字符数是'-c',单词数是'-w'。不带参就都输出咯。


四、保存结果到文件'>'、'>>'和'tee':

搞了这么多事当然想保存一下结果了。如果希望保存pipe的最终输出结果,可以直接用'> filename'或'>> filename',两者的不同在于后者发现文件存在时会添加在已存在文件末尾,而前者会覆盖掉原文件。

有的时候想要保存pipe中间某个环节的结果,就要用到'tee'了。tee好像管道里的“三通”,从直管中间引流出来。(是我脑洞太大还是linux作者脑洞大,tee的形状似乎也很符合?所以这个命名还是象形的?)

用例:

$ cat 10000lines.txt |grep '^#' | tee -a filename | wc -l
直接把tee接在想要保存的位置就可以。上例中第二步的结果就保存到了文件中。‘-a'表示文件重复时添加在已有文件末尾,不加就覆盖了。

注:文章部分引用自《鸟哥》