Post

awk 学习笔记(一)

本文主要受益于GUN

Introduction

awk 一般的执行方式为:

1
awk [program] [filenames]

表示对文件 filenames (可以有多个文件)执行 program 所指示的指令(也可以有多个指令),其中 program 即指令又可以分为 patternaction,即模式与动作,这些后面再谈。

若指令较长,也可以将指令保存在一个文件中,然后在命令行中指定文件执行:

1
awk -f [program-file] [filenames]

最简单的 awk 指令示例:

1
awk '{ print }' [filename]

上述指令用于输出 filenames 的内容,与 cat 指令类似。

在来一个例子:

1
awk '/li/ { print $0 }' mail-list

该指令用于找出 mail-list 中包含 li 的行,并将其打印出来,print $0 就是执行打印的指令,这里 $0 表示当前行(仅有 print 也是相同的意思)。 这里注意到 li 周围有 /,这表示 li 是一个被用于搜索的模式,即正则表达式。

我们上面已经提了,在 awk 中,指令 program 分为两个部分,模式 pattern 与动作 action。在一条指令中模式与动作可以不同时出现,但不可以都不出现。 若没有设置模式,则会对所有输入行执行动作;若没有设置动作,则默认会打印所有满足模式的输入行。因此如果要执行空动作,不应该是什么动作都不输入,而是输入 {},即明确指定空动作。

awk 还有一些其他的高级用法,比如打印文件中所有长度超过 80 的行:

1
awk 'length($0) > 80' file

这里因为只有模式没有动作,因此默认是打印满足模式的输入行。这里猜测 length 应该是 awk 内置的一个函数。

还比如打印整个文件中最长输入行的长度:

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

这里 END 的作用是告诉 awk 仅当所有输入都读完之后再执行 END 后面的指令。

再比如打印文件的行数:

1
awk 'END { print NR }' file

这里 NRawk 的内置变量,用于记录已经处理了多少行的数据。

The number of input records awk has processed since the beginning of the program’s execution (see How Input Is Split into Records). awk increments NR each time it reads a new record.

这里再介绍两个内置变量,后面可能会单独开一节介绍其他内置的变量和函数。

  • NF: 当前记录中数据域的个数,比如输入 1 2 3NF = 3,若输入 1 2 3 4NF = 4.
  • FNR: 当前文件中的当前记录编号。看起来 NRFNR 是一样的吼,但其实区别在于 FNR 在换文件的时候会被清0,但是 NR 并不会。可以理解为 NR 是全局变量,而 FNR 是一个作用域为文件的局部变量。StackOverflow

    The current record number in the current file. awk increments FNR each time it reads a new record (see How Input Is Split into Records). awk resets FNR to zero each time it starts a new input file.

使用 awk 对同一个记录执行两甚至多个动作?

awk 的工作方式是每次从输入读入一行数据,然后试图将输入与模式进行匹配,执行成功匹配的模式后面的动作,若有多个模式匹配,那么就按照动作在 awk 指令中出现的顺序来依次执行。

有点绕?来个例子:

1
2
3
4
5
6
7
8
9
10
11
12
# 打印所有权限为 644 的文件的信息
# 同时打印所有后缀为 md 文件的文件名(注意权限不一定是 644 哦)
ls -l | awk '/rw-rw-r--/ { print } /.*md/ { print $9 }'

# outputs:
# -rw-rw-r-- 1 xt xt  642  9月 16 12:43 pytest.ini
# -rw-rw-r-- 1 xt xt 2393  9月 16 12:43 README.md
# README.md
# -rw-rw-r-- 1 xt xt   48  9月 16 02:42 requirements.txt
# -rw-rw-r-- 1 xt xt  288  9月 16 12:43 setup.cfg
# test.md
# -rw-rw-r-- 1 xt xt   16  9月 30 17:43 test.sh

上例中因为 README.md 成功匹配了两个模式,因此执行了两个动作,且先是打印出了文件信息,然后再打印出文件名。

结束

我今天也是为了解决一个问题才来学了一点 awk 的,现在用上面的东西已经能解决我的问题了,所以今天就先点到为止。

This post is licensed under CC BY 4.0 by the author.