使用awk来进行文本的行处理

awk是一门按行处理文本的编程语言。
也许我们已经习惯用shell以外的语言来处理文本,但是有些时候,我们要在一些老古董的服务器上运行一些批量任务的时候,我们还是得重拾起这些依然锋利的工具。

基本用法

awk 基本以pattern{action} 为单位。
比如 awk "NR==2{print $0}" input.txt 输出input.txt中的第二行。
比如 awk "END{print "hello"}" input.txt 在完全处理完所有行之后,最后输出hello

awk 可以写成script形式。比如

1
2
3
#! /bin/awk -f

BEGIN { print "Don't Panic!" }

保存成hello之后,chmod +x hello之后,就可以执行了。

awk 中可以定义变量。

比如下面的例子中使用了一个变量max来输出data中最长的行的长度。

1
2
awk '{ if (length($0) > max) max = length($0) }
END { print max }' data

其他一些方法基本可以参照文档或者这本书

复杂的文本处理

假设我们需要比较txt1txt2 这两个文件,把只包含在txt1中的那些行输出到new_txt1, 同时把只包含在txt2中的那些行输出到new_txt2

1
awk 'NR==FNR{arr[$0];next} { if ($0 in arr) print $0 > "new_txt1"; else print $0 > "new_txt2"}' txt1 txt2

这里FNR可以理解为在当前读取文本中的行数,而NR则是所有文本中的当前行的计数,所以NR==FNR这个条件只有在第一个文本中为true,也就是说NR==FNR{arr[$0];next}将第一个文本中的所有行读到了一个变量arr之中。next读完直接不执行后面的内容,开始处理下面一行。所以只有读取到第二个文本的时候,才会开始执行{ if ($0 in arr) print $0 > "new_txt1"; else print $0 > "new_txt2"}

由此可以看出,awk由一个或者多个pattern{...}构成,如果没有指定pattern,则对于每一行,{...}中的内容总会执行。

awk