awk整理:简明总结与速查
[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 | if (condition) |
- 循环:
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 | function function_name(argument1, argument2, ...) { |
调用自定义函数则加上括号即可:function_name(foo, bar)
。
awk管道:与外部命令通信
awk的管道能够直接输出到指定的命令中。
- 通过管道
|
调用外部命令、传递数据。print xxx | "[COMMAND]"
:注意COMMAND必须使用双引号包裹。
通过管道调用wc命令统计单词个数:
1 | ➜ awk 'BEGIN{print "hello" " ,world" | "wc -w"}' |
- 通过双向管道
|&
调用外部命令,并允许管道两端进行读和写。print xxx |& "[COMMAND]"
:COMMAND通常赋值给一个临时变量,并在管道操作如|&
管道打开、close()函数关闭不需要使用的读写端、读取和写入到管道时使用这个临时变量。换句话说,这个临时变量就像是管道通信对象的抽象一样。
1 | BEGIN { |