【Linux】 字符串和文本处理工具 grep & sed & awk

时间:2024-01-13 08:15:50

Linux字符串&文本处理工具

  因为用linux的时候主要用到的还是字符交互界面,所以对字符串的处理变得十分重要。这篇介绍三个常用的字符串处理工具,包括grep,sed和awk

■  grep

  grep已经用得够多了不需要再特别地说明用法,就罗列一下几个不太熟悉的参数:

  -v  反选 比如常用ps -ef | grep -v grep来把grep本身的那条进程去掉

  -E  跟一个扩展正则表达式以增强grep的匹配功能。

  -i  忽略大小写地匹配

  -q  (常用于脚本)进行一个grep的判断,如果找到了返回true,否则返回false

  -w  和-E相对,去掉所有正则的转义,准确匹配某个pattern

  -n  grep的输出中带有匹配到项所在行的行号

  -r  递归地抓取整个目录

  -(数字n)  输出匹配项所在行的前n行和后n行的内容

■  sed 以行为单位的替换、新增、删除工具

  sed既可以做为一个独立命令出现也可以出现在管道右边

  当sed出现在管道右边的时候,其对左边过来的内容进行一些处理。而当sed独立出现时可以加参数-i后面接上一个文件,可以直接编辑文件的内容。如果觉得直接改不太保险可以用参数-i.bak(没错,直接加上.bak),sed会自动为源文件搞一个.bak的备份文件

  ●  sed用法:

    sed [OPTION] [ACTION] [FILE]

  action的部分基本上是这样的:'[n1[,n2]]function',如果想要连续执行多个action的话那么可以用-e参数。就是sed -e 'action1' -e 'action2'这样的形式。也可以直接用分号:sed 'action1;action2'这样的形式。

  n1和n2为可选项,可以用数字或者^,$符号,代表某些特定的行(^表示首行,$的话表示最后一行),表示后面的function在指定的这一行或几行之间展开。

  而function有以下参数:

    a:指append,后接上字符串,意思是在指定行后面新加入一行,内容为a后面跟的字符串。比如sed -i '2 a INSERTTEXT' test.txt就可以在test.txt现在的第二行后面加上一行,内容是"INSERTTEXT"

    d:指delete,删除指定一行或多行,注意d参数是跟在行号后面的,比如sed '2,5d' test.txt就是删除了文件中的第2至5行

    i:指insert,后接上字符串,和append相对,在指定行的上方加入一个新行

    s:指substitute,最常用的一个参数,其基本格式是's/old/new/[n]',old是被替换的字符串,new是新替换进的字符串,而n是一个可选项,可以写数字或者g。数字的意思是只替换一行中的第n个old,而g是指替换全部old,如果写了ng就是说替换第n个old之后到行末的所有的old

    y:用参数y可以对原文进行字符级别的替换,y的用法和s类似,如'y/OLD/NEW/',相当于把原文中所有的O替换成N,L换成E,D换成W。显然,要求OLD和NEW的长度应该相等,否则sed会报错。

    &:表示已经匹配到的字符串,通常用在正则匹配中,比如's/正则表达式/&ok/g'表示把所有匹配正则表达式的字符串后面都加上ok。

    /:'/pattern/'的作用就是定位含有pattern的行。它可以替代n1,n2那样死板的指定行的方法。比如sed '/pattern/!i INSERT'就是除了匹配到pattern的行,其余地行在前面一行都插入内容为INSERT的一行新行。

    !:写在参数前面否定,比如'/pattern/!d'就是不删除匹配到pattern的行

    p:常用在s的最后参数位置,即's/old/new/p'的形式。这么做可以让sed在输出显示的时候只输出被修改过的行。这么做的话需要配上命令的参数-n,最后的命令应该是像sed -n 's/old/new/p' test.txt这样的形式。

  ●  sed脚本

  sed -f <script> <file>可以应用sed脚本script到file中。sed脚本中每一行都写有一个action,应用到一个文件之后就按顺序逐条sed执行。最后sed会把处理完所有function的文件内容输出到stdout上。当sed的需求比较复杂时可以考虑这么干。

  sed的参数很多,再配合上正则表达式就使得功能十分强大了,但同时也使得功能超级复杂。。我的感觉是,如果复杂度到达一定程度的话,还不如用更加熟悉的python来解决。总之上面罗列的都是些常用的sed参数,如果想要更加详细的可以那本蓝蓝的shell脚本实践指南P155,上面有更加全的参数列表和用法。以上。

■  awk 以列为单位的文本处理工具

  awk会遍历读取文件的每一行然后经过一些处理把它视作一条记录来进行数据的读取。和sed一样,awk可以作为独立命令或管道右边两种方式出现。其基本用法的格式是awk <pattern> <file>。pattern是用户根据自己需要些的一个awk表达式。

  awk默认以空格作为分隔符,对每一行的内容进行自动的分隔操作。每一个被分隔出来的部分被称为域(field),在awk的表达式中用$n来表示。$0表示读取到的整行内容,$1表示第一个域,$2表示第二个以此类推。比较经典的一个应用如下:

  test.txt内容:

Frank    22    Male    13512345678
Bob 23 Male 13587654321

  然后执行awk '{print $1"s number is "$4}' test.txt输出就是Franks number is 13512345678\nBobs number is 13587654321

  可以注意到,s number is这部分是常量,需要用引号特别括起来。而print语句需要用大括号括起来

  ●  自定义分隔符

  如果不要空白作为分隔,而想自己制定的话可以用-F <sep>来指定分隔符

  ●  内置变量

  awk内置了几个变量供用户使用,比如:

    NF  当前行的字段总数

    NR  当前行是第几行

    FS  当前的分隔符,默认是space

  这些变量可以给awk表达式加上一些条件。比如awk 'NR!=1{print $1}'打印出除了第一行外所有行的第一个字段

  ●  表达式条件

  正如上面这个例子,在进行操作之前可以有些判断条件,判断条件式写在print之前,相当于让awk在输出前做一个判断。同时也可以应用上FS这些变量。比如:

  awk -F : '$3<10 {print $1}' test.txt的意义就是以冒号为分隔符读取每一行,且当该行的第三个域的值小于10的情况下才打印出这行的第一个域的值。

  判断式中条件可以是<,>,<=,>=,==,!=等。

  和sed一样,awk有自己的一套表达式语言,功能强大但复杂,上述常用的可以用,实在用不出来就看看文档或者用python把。。