[TOC]

awk的名字取自三位作者的姓的首字母。在Linux中使用的awk实际上已经不是最原始的awk了,而是GNU维护的gawk,但是在命令行中仍然保持使用awk命令。

参数与命令

awk [options] 'COMMAND' file
awk [options] '/pattern/' file
awk [options] 'condition' file
awk [options] '/pattern/ COMMAND' file
awk [options] 'condition COMMAND' file

  • 命令:awk命令必须使用单引号包裹,不能使用双引号
  • COMMAND为空时默认调用print函数打印当前行
  • pattern或condition为空时默认所有行都匹配

awk命令语句主体:/pattern/ {COMMAND}。pattern正则表达式匹配成功后执行COMMAND。其中pattern为空时默认每行都匹配,COMMAND为空时默认为打印该行。其中,/pattern/可以换成条件表达式,以条件表达式的返回值是否为真来决定是否匹配该行。awk 'length($0) > 10 {...}' file通过内置函数计算当前行的长度,大于10时执行{COMMAND}。

参数 作用 说明
-v 定义预定义变量 定义一个变量,可以在命令语句块中使用。-v var=...
-F 指定Field separator 对awk预定义的变量FS进行赋值;awk处理每一行时会对行做分隔(split),分隔的基准就是FS定义的字符(默认为空格和tab)-F:让awk按’:’分隔每一行
–lint 对awk命令和指定的file做lint检查 如果输入的awk命令或file有异常或警告信息,则会被打印出来(如输入的awk命令的主体语句块不合理、file不是文本文件)
-f 从-f指定的文件中读取awk命令 awk命令可以作为参数,也可以通过文件读取
–profile[=file] 将awk命令进行格式化并输出到file中(缺省为awkprof.out) 相当于从命令行生成格式化的能传递给-f参数的awk命令文件

预定义的变量

awk --dump-variables ''可以生成awkvars.out,它记录了awk预定义的变量。

变量名 作用 说明
ARGC awk命令行参数个数 不包括单引号内的awk命令
ARGV 存储命令行参数的数组 不存储单引号内的awk命令
CONVFMT 数字格式化转换时的保留小数位 默认%.6g即保留6位小数
OFMT 数字输出时的格式化小数位
FNR File Number Record:(已处理的)文件行号 当前文件已处理的行号(行号从1开始数awk 'NR < 3' file打印文件前2行
FS Field Separator: 列分隔符 awk根据这个变量指定的分隔符来分隔每一列,默认为空格或tab,所以awk默认按照空字符分隔每一行内的各个单词
RS Record Separator: 行分隔符 awk根据这个变量指定的分隔符来分隔每一行,默认为\n
OFS Output Field Separator:输出打印时各打印数据之间的分隔符 awk打印数据时(显式或隐式调用print),各数据之间使用OFS指定的字符进行间隔。awk -v OFS="-" '' file将文件的空格和tab替换为’-‘输出
ORS Output Record Separator:输出打印时各行之间的分隔符 同OFS
NF Number of Fields 当前行被分隔出了多少列
NR Number of Record: (已处理的)总行号 awk处理多个文件时所有文件的已处理行号都会加到这里;FNR仅记录单个文件
RLENGTH 模式匹配中匹配到的字符串的长度
RSTART 模式匹配中第一个匹配到的字符串的位置
$0 $n 被FS分隔的每一列
FIELDWIDTHS 设置分割行时使用固定的空格(取代FS) 设置后,GAWK会以固定的空格长度来分割每一行。
IGNORECASE 大小写敏感 缺省为0——awk默认模式匹配的pattern大小写不敏感;设置为1则大小写敏感
LINT 检查 设置不同的LINT等级会让awk检查命令、文件,高级别的lint甚至会触发fatal拒绝执行有lint异常的命令

主体块与BEGIN块、END块

awk会对读入的每一行执行操作,主体块内的命令就定义了每一行都执行的操作。主体块使用大括号{}包裹。而在awk开始处理前和完成所有处理后,可以通过BEGIN块和END块定义操作,分别用BEGIN{…}和END{…}定义。BEGIN块和END块仅执行一次(分别在处理第一行之前和处理完成最后一行后)。

awk 'BEGIN{...}{...}END{...}' file

速记:带关键字的{}BEGIN{...}END{...}是预处理块、收尾块,而不带关键字的{...}是主体块:每一行都会被该块内的指令处理。

打印命令print、输出命令printf

输出变量值(包括表示整行的$0、表示列的$1等)在{}语句块中使用print。需要格式化输出时使用printf(类似C语言)。
awk 'BEGIN{printf "---hello %s---\n", FS}{print $1}' file

列的分隔和Field Separator

awk逐行处理文件,并以变量FS(Field Separator)指定的分隔符(默认是空格和tab)来分隔行。基于分隔符将行分隔得到多个字段(Field),每个字段分别用$1、$2、$3等表示,并用$0表示整行。

临时变量和数组

awk可以在COMMAND中定义和使用变量,直接用var_name=var_value即可。其中变量不需要初始化即可直接操作,因为它们自动被初始化为0。如awk '{++cnt}END{print "cnt: ", cnt}' file直接使用了cnt。

数组创建与变量一样,不需要先初始化。arr[i]=foo。删除数组使用delete命令:delete arr[i]

注意,数组的下表不要求类型,它可以使用字符串。

  • 使用一维数组模拟多维数组
    awk没有内置的多维数组,它仅支持一维数组。通常使用字符串来实现复杂的数组。如arr["0,1"]=1就是模拟的二维数组,它通过字符串作为key解决了数字作为key只支持一维数组的问题。

运算符

awk运算符几乎等同于C语言。

运算符 作用 说明
+
-
*
/
% 求余 awk 'BEGIN { x = 50; y = 20; print "(x % y) = ", (x % y) }'
++、– 自加/自减 awk 'BEGIN { x = 15; y = ++x; printf "x = %d, y = %d\n", x, y }'
+=、-=、/=、*=、%= 自运算 x+=y –> x=x+y
^= 幂运算 x^=2 –> x=x^2 计算x的平方
**= 幂运算 等同于^=:x**=y –> x^=y
==、!=、<、<=、>、>= 比较 awk 'BEGIN{if (a == b) {CMD...}}'
&&、||、!、... ? ... : ... 逻辑运算
一元+、一元- 对变量(数字和字符串)乘以1或-1,并转为数字 通常用于判断变量是否为数字或进行转换x = -10; x = +x; x=-x; y="y"; y=+y; xy="-10"; xy=-xy; x=+x后仍为-10,接下来由-x转为10;y被转为0因为它不是数字也不是数字字符串;xy变成10,因为乘上了-1。
空格 字符串拼接 空格两边的字符串被拼接起来 '{str="s" "tr"}'
for (index in arr) 数组foreach
~ 匹配运算符 ‘$0 ~ “hello”‘ 在本行中查找匹配”hello”的字符串

条件分支与循环

  • if语句:awk '{val="hello"; if (val == "") {val="world";print val}}' file。其中if语句内只有一个命令时(即不需要分号分隔),那么可以省略if的{}。
1
2
3
4
5
6
if (condition)
{action-1; action-1-1}
else if
action-2
else
action-3
  • 循环:for do-while while break continue与C语言几乎一样。

内置函数

详细参考可以查参考文献。这里仅列出可能用得上的函数

函数名 作用
int(…) 将括号内的表达式转换为整数
rand() 返回[0,1)的随机浮点数
srand(…) 以种子(缺省为当前时间戳)返回随机整数
gsub(regex, sub, string) 将string中匹配regex的字符串替换为sub
index(str, sub) 返回是否str包含sub
length(str) 返回str长度
match(str, regex) 查找匹配模式的子串位置
split(str, arr, regex) 字符串分割
substr 获取子串
tolowwer、toupper 大小写转换
and 逻辑与函数
compl 按位取反函数
lshirt rshift 左移右移函数
or xor 或、异或
getline 读入下一行并处理(包括对行做分割,对$0、$1等赋值)
next 跳过本行,处理下一行(与getline的差异在于,当前行执行的命令、缓冲不会带入下一行;而getline相当于把下一行的内容替换进来)
return return是一个函数,在自定义函数、expr中返回数据
system(…) 执行系统命令

自定义函数

awk定义函数与shell脚本一模一样:

1
2
3
function function_name(argument1, argument2, ...) { 
function body
}

调用自定义函数则加上括号即可:function_name(foo, bar)

awk管道:与外部命令通信

awk的管道能够直接输出到指定的命令中。

  • 通过管道|调用外部命令、传递数据。
    print xxx | "[COMMAND]":注意COMMAND必须使用双引号包裹。

通过管道调用wc命令统计单词个数:

1
2
➜ awk 'BEGIN{print "hello" " ,world" | "wc -w"}'
2
  • 通过双向管道|&调用外部命令,并允许管道两端进行读和写。
    print xxx |& "[COMMAND]":COMMAND通常赋值给一个临时变量,并在管道操作如|&管道打开、close()函数关闭不需要使用的读写端、读取和写入到管道时使用这个临时变量。换句话说,这个临时变量就像是管道通信对象的抽象一样。
1
2
3
4
5
6
7
8
9
BEGIN {
cmd = "tr [a-z] [A-Z]"
print "hello, world !!!" |& cmd
close(cmd, "to")

cmd |& getline out
print out;
close(cmd);
}

参考文献

  1. awk简单教程