入门
awk在文本处理脚本shell里很常用,它从管道|或文件中读取每一行,然后按照一定规则把每行自动分成多列,默认使用空格自动分列。在awk里面,空格可以是空白字符、TAB制表符。分列可以让awk脚本很方便地引用这些分隔开的值,$1表示第一列,$2表示第二列,等等以此类推,当然$后面的数字可以是个很大的值,比如$1024。另外,在awk中使用$0表示整行,$NF表示最后一列。
先来看个示例
1
 |  | 
$1是this,$2是seems,$7和$NF是example,在该例子中使用空格分隔成7列,完整语法是这样的
1
 |  | 
可以看到awk多了一个-F参数,通过该参数可以设置各种分隔符,单字符、多字符都能很好的支持,同样的示例我可以添加-F' like '这样的多字符分隔符,可以得到结果this seems.
1
 |  | 
除了NF,awk还有一些其他内置变量,见下表
| 内置变量 | 变量描述 | 
|---|---|
| CONVFMT | 转换数字使用的格式,默认为:%.6g | 
| FS | 分列使用的正则表达式,可以通过-Ffs来设置 | 
| NF | 当前行分隔后的列数 | 
| NR | 当前行的序号 | 
| FNR | 当前文件中当前行的序号 | 
| FILENAME | 当前输入文件名 | 
| RS | 行分隔符,默认为换行符\n | 
| OFS | 输出列间隔符,默认为空格 | 
| ORS | 输出行分隔符,默认为换行符\n | 
| OFMT | 数字的输出格式,默认为:%.6g | 
| SUBSEP | 下标分隔符,默认为:\034(双引号),比如foo[“A”,“B”],实际通过foo[“A\034B”]来访问 | 
| ARGC | awk参数数量,可赋值 | 
| ARGV | awk参数列表,可赋值,0..ARGC-1,非0索引表示输入文件名 | 
| ENVIRON | 环境变量列表,通过下标变量名(ENVIRON[变量名])来访问,环境变量var=value,通过ENVIRON[var]=value方式存储 | 
"="
1
 |  | 
0 awk 1 ArenaServer.cs 2 LogicServer.cs 3 Server.cs 4 Utils.cs
1
 |  | 
DISPLAY = /private/tmp/com.apple.launchd.eKuWVlBt3M/org.macosforge.xquartz:0 Apple_PubSub_Socket_Render = /private/tmp/com.apple.launchd.grOg8OMLVo/Render OLDPWD = /Users/larryhou/Documents/next/trunk LOGNAME = larryhou XPC_SERVICE_NAME = 0 JAVA_HOME = /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home USER = larryhou PATH = /usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Applications/Server.app/Contents/ServerRoot/usr/bin:/Applications/Server.app/Contents/ServerRoot/usr/sbin:/Applications/Wireshark.app/Contents/MacOS __CF_USER_TEXT_ENCODING = 0x1F5:0x0:0x0 TERM_SESSION_ID = A39F566B-15B3-4423-9716-491208377960 TERM_PROGRAM_VERSION = 388 TERM = xterm-256color SHLVL = 1 TMPDIR = /var/folders/gb/2wdjrlq53fbdf0xbs145cv2m0000gn/T/ SECURITYSESSIONID = 186a6 HOME = /Users/larryhou SHELL = /bin/bash TERM_PROGRAM = Apple_Terminal LC_CTYPE = UTF-8 _ = /usr/bin/awk PWD = /Users/larryhou/Documents/next/trunk/TheNextMOBA/Assets/Scripts/Service/Network SSH_AUTH_SOCK = /private/tmp/com.apple.launchd.eDbmxn43sK/Listeners XPC_FLAGS = 0x0
1
 |  | 
Server.cs.meta:01 fileFormatVersion: 2
Server.cs.meta:02 guid: c265c6b6a7a784f3bb1417ce67e9df3e
Server.cs.meta:03 timeCreated: 1456236560
Server.cs.meta:04 licenseType: Free
Server.cs.meta:05 MonoImporter:
Server.cs.meta:06   serializedVersion: 2
Server.cs.meta:07   defaultReferences: []
Server.cs.meta:08   executionOrder: 0
Server.cs.meta:09   icon: {instanceID: 0}
Server.cs.meta:10   userData: 
Server.cs.meta:11   assetBundleName: 
Server.cs.meta:12   assetBundleVariant: 
正则表达式
上面通过分隔符分列是awk的基本功能,awk还可以和正则表达式结合相结合做出复杂的效果
1048592             |FowTexture:Init ()|Color[]             
262160              |AStar:.ctor (Map)|Int32[]             
196684              |TheNextMoba.Module.Arena.ArenaResourceLoader:OnItemLoadSuccess (string,object)|Byte[]              
192016              |Morefun.LockStep.LockstepProfiler/Stat:CreateFrameContext ()|FrameContext[]      
131088              |SignedDistanceField:.ctor (Map,int)|Int16[]             
81936               |GameObjectUtil:Init ()|String[]            
65568               |TheNext.Moba.Logic.FOWManager:Init ()|Byte[,]             
65568               |TheNext.Moba.Logic.FOWManager:Init ()|Byte[,]             
65568               |TheNext.Moba.Logic.FOWSystem:Init (TheNext.Moba.Logic.EnmTeamID,TheNext.Moba.Logic.IFOWSystem)|Byte[,]             
65568               |TheNext.Moba.Logic.FOWSystem:Init (TheNext.Moba.Logic.EnmTeamID,TheNext.Moba.Logic.IFOWSystem)|Byte[,] 
1
 |  | 
1048592             |FowTexture:Init ()|Color[]             
81936               |GameObjectUtil:Init ()|String[]            
65568               |TheNext.Moba.Logic.FOWManager:Init ()|Byte[,]             
65568               |TheNext.Moba.Logic.FOWManager:Init ()|Byte[,]             
65568               |TheNext.Moba.Logic.FOWSystem:Init (TheNext.Moba.Logic.EnmTeamID,TheNext.Moba.Logic.IFOWSystem)|Byte[,]             
65568               |TheNext.Moba.Logic.FOWSystem:Init (TheNext.Moba.Logic.EnmTeamID,TheNext.Moba.Logic.IFOWSystem)|Byte[,] 
通过awk '/Init/'这个简单的例子可以知道,在双斜杠'//'中间可以添加正则表达式,正则表达式的作用过滤出匹配的行 然后再执行花括号里面{}逻辑,该示例中正则对整行进行匹配操作,也可以对某一列执行匹配
1
 |  | 
脚本用|分隔符分列,把正则表达式应用到第二列进行匹配
1
 |  | 
1048592              Color[]             
81936                String[]            
65568                Byte[,]             
65568                Byte[,]             
65568                Byte[,]             
65568                Byte[,] 
表达式
awk也支持常见的流程控制语句if...else、for、for...in、while、do...while
for循环和三元表达式
1
 |  | 
1 2  |  | 
for循环和if表达式
1
 |  | 
1 2 3 4 5  |  | 
C0:A8:00:69
for...in和split
1
 |  | 
while
1
 |  | 
FowTexture:Init ()
Color[]             
AStar:.ctor (Map)
Int32[]             
TheNextMoba.Module.Arena.ArenaResourceLoader:OnItemLoadSuccess (string,object)
Byte[]              
Morefun.LockStep.LockstepProfiler/Stat:CreateFrameContext ()
FrameContext[]      
SignedDistanceField:.ctor (Map,int)
Int16[]         
其他各种表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  |  | 
可以在表达式中使用的awk内置函数
| 函数名 | 函数描述 | 
|---|---|
| length | 字符串长度 | 
| rand | 生成(0<=x<1)范围的随机数 | 
| srand | 设置随机种子并返回之前的随机种子 | 
| int | 截尾转换成整数 | 
| substr(s,m,n) | 返回字符串s自m位置(索引从1开始)开始的n个字符 | 
| index(s,t) | 如果字符串s中包含t,则返回t在字符串中出现的位置(从1开始),否则返回0 | 
| match(s,r) | 返回字符串s匹配正则表达式r的位置(从1开始) | 
| split(s,a,fs) | 把字符串s通过正则fs分隔成数组a,并返回数组a长度n,如果fs未设置,则使用FS分隔符 | 
| sub(r,t,s) | 在字符串s中,使用正则表达式r首次匹配的位置替换成t,如果s未设置,则使用$0 | 
| gsub(r,t,s) | 与sub(r,t,s)参数相同,不过会把匹配的字符串全部替换,并返回替换的次数 | 
| sprintf(fmt,expr,…) | 使用与printf相同的样式fmt格式表达式列表 | 
| system(cmd) | 执行cmd并返回退出状态码 | 
| tolower(str) | 把字符串str转换成小写 | 
| toupper(str) | 把字符串str转换成大写 | 
以及各种运算符
| 运算符 | 描述 | 
|---|---|
| =,+=,-=,*=,/=,%=,^=,**= | 赋值 | 
| ?: | C条件表达式,三元表达式 | 
| || | 逻辑或 | 
| && | 逻辑与 | 
| ~,~! | 匹配正则表达式和不匹配正则表达式 | 
| <,<=,>,>=,!=,== | 关系运算符 | 
| 空格 | 连接 | 
| +,- | 加,减 | 
| *,/,% | 乘,除与求余 | 
| +,-,! | 一元加,减和逻辑非 | 
| ^,*** | 求幂 | 
| ++,-- | 增加或减少,作为前缀或后缀 | 
| $ | 字段引用 | 
| in | 数组成员 | 
综合示例
下面这个示例使用awk做了一个相对比较复杂的事情:把第二列相同的行归为一类,并把相同类的第一列数值相加求和,并输出汇总结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  |  | 
656,632 96 System.Collections.Generic.List`1:.ctor(System.Collections.Generic.IEnumerable`1 ) Int32[] #315133 859,648 64 System.Collections.Generic.Dictionary`2 
如果在awk操作里面使用单引号'则需要转义,可以通过'\''来实现,上面这个示例中使用了两次单引号'。另外,使用了printf对数值进行千分位格式化,脚本使用的数据源文件通过链接下载。
延伸阅读:
Awk User’s Guide:Very Simple
Awk User’s Guide:Fields
awk用法