• Linux 文本处理三剑客:grep、sed 和 awk


    awk、grep、sed是linux操作文本的三大利器,合称文本三剑客,也是必须掌握的linux命令之一。三者的功能都是处理文本,但侧重点各不相同,其中属awk功能最强大,但也最复杂。grep更适合单纯的查找或匹配文本,sed更适合编辑匹配到的文本,awk更适合格式化文本,对文本进行较复杂格式处理。

    grep

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

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

    命令的基本格式:

    grep [option] pattern file
    
    • 1

    即便不熟悉这个命令,应该大多数同学也用过查询进程的命令:

    ps -ef|grep xxxx
    
    • 1

    这就是 grep 的一个基本用法,从所有进程中搜索某个进程。

    grep 常用的参数如下:

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

    前三个 A、B、C 参数很容易理解,举个栗子,假设我们有一个文件,文件名是 test,内容是从 1 到 9,每个数字一行:

    grep -A2 7 test
    7
    8
    9
    
    • 1
    • 2
    • 3
    • 4

    -A2 7 的效果就是找到 7 ,然后输出 7 后面两行。

    同理,-B2 7-C2 7就是找到 7 ,然后分别输出 7 前面两行和前后两行:

    grep -B2 7 test
    5
    6
    7grep -C2 7 test
    5
    6
    7
    8
    9
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    继续,假设我们有个名叫 test 的文件内容如下:

    cat test
    aaaa
    bbbbbb
    AAAaaa
    BBBBASDABBDA
    
    • 1
    • 2
    • 3
    • 4
    • 5

    grep -c命令的作用就是输出匹配到的行数,比如我们想找包含aaa的有几行,一眼就能看出来有两行,第一行和第三行都包含:

    grep -c aaa test
    2
    
    • 1
    • 2

    grep -e命令是实现多个匹配之间的关系,比如我们想找包含aaaa或者bbbb的,显然应该返回第一行和第二行:

    grep -e aaaa -e bbbb test
    aaaa
    bbbbbb
    
    • 1
    • 2
    • 3

    grep -F相当于fgrep命令,就是将pattern视为固定字符串。比如搜索'aa*'不带-F和带上,区别如下:

    grep 'aa*' test
    aaaa
    AAAaaa
    
    ➜ grep -F 'aa*' test
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以看到第二次就找不到了,因为搜索的是 aa*这个字符串,而不是正则表达式。

    grep -f 文件名的使用方法是把后面这个文件里的内容当做pattern。比如我们有个文件,名字是 grep.txt,然后内容是aa*,使用方法如下:

    grep -f grep.txt test
    aaaa
    AAAaaa
    
    • 1
    • 2
    • 3

    实际上等同于grep 'aa*' test

    grep -i --ignore-case作用是忽略大小写。

    grep -n显示匹配的行号,就是多显示了个行号,不用细说。

    grep -o仅显示匹配到的字符串,还是用刚才的aa*距离,之前显示的都是匹配到的字符所在的整行,这个命令是只显示匹配到的字符:

    ➜ grep -o 'aa*' test
    aaaa
    aaa
    
    • 1
    • 2
    • 3

    grep -q不打印匹配结果。刚看到这个我疑惑了半天,让你搜索字符串,你不给我结果那有啥用?然后发现还有一条很多教程没说:如果有匹配的内容则立即返回状态值 0。所以一般用在shell脚本中,在 if 判断里面。

    grep -s不显示错误信息,不解释。

    grep -v显示不被匹配到的行,相当于[^]反向匹配,最常见的还是用在查找线程的命令里,有时候会打印grep线程,可以再加上这么一个去除自己:

    ps -ef|grep Typora
      501 91616     1   0 五11上午 ??        13:39.32 /Applications/Typora.app/Contents/MacOS/Typora
      501 14814 93748   0  5:33下午 ttys002    0:00.00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn Typora
    
    ➜ ps -ef|grep Typora|grep -v grep
      501 91616     1   0 五11上午 ??        13:39.32 /Applications/Typora.app/Contents/MacOS/Typora
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    可以看到第二次就没有打印grep线程自身

    grep -w匹配整个单词,只有完全符合pattern的单次才会匹配到:

    grep aaa test
    aaaa
    AAAaaa
    
    ➜ grep -w aaa test
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以看到第二次结果为空,因为没有aaa这个单词。

    关于正则的高级用法就不再深入研究了,改日再统一整理。

    sed

    sed 命令的作用是利用脚本来处理文本文件。使用方法:

    sed [-hnV][-e<script>][-f<script文件>][文本文件]
    
    • 1

    参数说明

    • -e