awk 学习笔记(一)
本文主要受益于GUN
Introduction
awk
一般的执行方式为:
1
awk [program] [filenames]
表示对文件 filenames
(可以有多个文件)执行 program
所指示的指令(也可以有多个指令),其中 program
即指令又可以分为 pattern
和 action
,即模式与动作,这些后面再谈。
若指令较长,也可以将指令保存在一个文件中,然后在命令行中指定文件执行:
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
这里 NR
是 awk
的内置变量,用于记录已经处理了多少行的数据。
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 3
则NF = 3
,若输入1 2 3 4
则NF = 4
.FNR
: 当前文件中的当前记录编号。看起来NR
和FNR
是一样的吼,但其实区别在于FNR
在换文件的时候会被清0,但是NR
并不会。可以理解为NR
是全局变量,而FNR
是一个作用域为文件的局部变量。StackOverflowThe 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
的,现在用上面的东西已经能解决我的问题了,所以今天就先点到为止。