Linux 命令 - awk

1 awk 与 grep 的联系与区别

两者都是来处理标准输入或者文本的。

grep 是以行为单位进行处理。不过,awk 的处理粒度更细一点,它首先将每一行通过分隔符划分成多个域(field,\$1 代表第一个域,\$2 代表第二个域,等等。\$0 代表这一行分隔前的情形)。然后以域为基本单位进一步处理。

2 awk

调用形式为:
awk 'BEGIN {commands} pattern {commands} END {commands}' file

其中,

  • BEGIN {commands} 表示执行 awk 命令开始前要执行的命令。可以省略;
  • END {commands} 表示执行完 awk 命令后要执行的命令。可以省略。

pattern 有如下几种形式:

  • 正则表达式

    要用 /(定界符号)包裹起来,且不支持 {n,m} 这种扩展的正则表达式。

  • 关系表达式。比如:
    '$2=="hello" {print $2}'
  • 空,表示对任意一行都满足执行对应 commands 的条件。

commands 中可以使用 C 中的一些表达式和函数,比如 if ... else ... for ... while ... printf 等等。

注意:如果 commands 为空,则表示打印匹配的整行。

3 awk 的一些常用参数

3.1 -F

默认情况下,以空格作为域分隔符。不过也可以通过 -F 参数指定一个字符或者一个字符串作为域分隔符。

比如:

1
2
3
4
5
6
7
8
9
10
# abc: cde
# hello: nju
# hello: world
# hello: bye
cat b_2.txt

# lineno: 2 1: hello 2: nju
# lineno: 3 1: hello 2: world
# lineno: 4 1: hello 2: bye
awk -F ": " '/hello/ {printf("lineno: %s 1: %s 2: %s\n",NR,$1,$2)}' b_2.txt'

其中,printf 是 C 语言中的打印函数。NR (Number of Rows) 代表当前已匹配的行数,因此可以用它来记录行号。另外,NF (Number of Fields) 代表当前行所划分出的域的个数。

-F 也可以指定多个分隔符,如下:
awk -F '[ :-]' '$3==10 && $4>=21 {print}'

3.2 -v

awk 中的 pattern 和 commands是不能直接使用外部的一些变量的。此时需要通过 -v 参数赋值到 awk 中的变量中。比如:

1
2
3
var1=hello
var2=world
awk -v var1=$var1 -v var2=$var2 '$2==var1 && $3==var2 {print $2}' test.txt

4 基于 find、awk、grep 和 sort 跨文件查询日志

查询多个日志文件中 2018-07-28 21:00:002018-08-04 12:00:00 之间的所有日志,并按时间先后顺序显示:
find . -name "*.log" | xargs -I {} awk -F '[ :-]' '$1$2$3$4>="2018072821" && $1$2$3$4<="2018080412"' {} | sort


Reference