sed与awk-第十一章-awk系列产品
第十一章 awk的系列产品
原始的awk(V7 最早版本,功能残缺)
七十年代第七版UNIX自带最老awk,大量现代awk特性没有。
转义序列
仅支持:\t \n \\ \";
\b \r \f大多厂商后期才追加。
求幂
没有 ^、^=、**、**= 求幂运算符。
C语言三元条件表达式
不支持 条件 ? 真表达式 : 假表达式,只能写if‑else。
变量直接作为布尔模式不支持
老版本不能写:
|
|
必须写比较表达式:
|
|
伪动态正则
原始awk正则必须写死在脚本里,不能直接把awk变量当做正则模式。
变通方案:shell拼接字符串传入awk。
shell参数默认值写法:
控制流行为差异
- 如果脚本只有BEGIN块,没有其他规则:POSIX‑awk执行完BEGIN直接退出;原始V7‑awk还会继续等待输入。
- 解决:要么传
/dev/null作为输入文件,要么在BEGIN末尾写exit。
- 解决:要么传
- BEGIN、END只能各出现一次,并且必须分别放在脚本开头、脚本末尾。
字段分隔
字段分割逻辑大体相同,但FS不能使用正则表达式。
数组功能残缺
- 没有
delete array[下标]删除数组元素;只能赋值为空字符串,代码自己判断跳过空值。 - 没有
in操作符,不能用if(key in arr)判断下标是否存在;只能for(key in arr)循环遍历全部元素比对。
getline
原始V7‑awk完全没有getline;部分厂商补丁只实现最简单读主输入流的getline,不支持读文件、管道,也没有FNR。
内置函数(原始awk)
表11‑1 原始awk内置字符串函数
| 函数 | 说明 |
|---|---|
index(s,t) |
返回子串t在s中的位置,找不到返回0 |
length(s) |
返回字符串长度;无参数取$0 |
split(s,a,sep) |
拆分字符串到数组a,返回元素个数 |
sprintf(fmt,expr) |
格式化,返回字符串 |
substr(s,p,n) |
截取子串 |
表11‑2 原始awk算术函数
| 函数 | 说明 |
|---|---|
exp(x) |
e的x次幂 |
int(x) |
截断取整 |
log(x) |
自然对数 |
sqrt(x) |
平方根 |
原始awk:不支持用户自定义function函数。
原始awk内置变量
表11‑3
| 变量 | 含义 |
|---|---|
FILENAME |
当前输入文件名 |
FS |
输入字段分隔符,默认空格,一行(记录)内部,切分成 $1 $2 |
NF |
当前记录字段数 |
OFMT |
数字输出转换格式,默认%.6g |
OFS |
输出字段分隔符,print $1,$2 逗号输出时,字段之间用什么隔开,默认空格 |
ORS |
输出记录分隔符,每一条记录 print 输出完末尾加什么,默认换行\n |
RS |
把整个大文件切分成一条条记录(行),默认换行\n;RS=""代表空行分隔多条记录 |
原始awk没有
CONVFMT,数字转字符串使用OFMT。
可免费使用的awk实现
三个主流免费版本:
- Bell Labs awk(nawk,Brian Kernighan官方原版)
- GNU awk(gawk,Linux默认)
- mawk,Michael Brennan实现,速度很快
下面是三者都支持的扩展(不属于POSIX标准,可移植脚本慎用)
共有的扩展功能
delete array不带下标,一次性清空整个数组
注意:数组一旦定义为数组,就不能再当做普通标量变量使用。
- 字符拆分扩展
FS="":每一个字符单独作为一个字段。split(str,arr,""):把字符串每个字符拆进数组。
POSIX标准没有该能力;没有扩展只能反复调用
substr()逐个取字符。
fflush()刷新输出缓冲区
POSIX没有;参数是文件名/管道;强制把缓冲区数据写入文件,不等缓冲区填满。
- 通用特殊文件名(写字符串引号包裹)
| 文件名 | 描述 |
|---|---|
/dev/stdin |
标准输入;mawk不支持,mawk用"-" |
/dev/stdout |
标准输出 |
/dev/stderr |
标准错误输出 |
/dev/tty |
用户终端屏幕;所有版本都能用 |
示例,打印错误直接输出到终端,不受重定向影响:
nextfile语句
跳过当前整个文件,直接处理下一个输入文件;
next是跳过单条记录,nextfile跳过整个文件。不属于POSIX。
- RS支持正则表达式(gawk、mawk)
- POSIX标准:RS只能单个字符;
- gawk/mawk:RS可以写正则;gawk额外提供
RT变量保存实际匹配到的分隔文本。
Bell Labs awk(nawk)
awk作者官方实现;System V 4、SunOS4.1.x自带。
- 1987版本:实现大部分POSIX特性,缺少CONVFMT,用OFMT。
- 1989版本新增:
-v选项(BEGIN前设置变量)tolower()、toupper()- 多个
‑f加载脚本库文件 ENVIRON环境数组- srand()返回旧种子;printf动态宽度精度
- 1993公开源代码,增加
fflush(),增加CONVFMT。 - 1996版本吸收gawk/mawk很多扩展特性。
GNU awk — gawk(Linux系统默认awk)
功能最强扩展最多;很多扩展非POSIX。
gawk命令行选项
| 选项 | 功能 |
|---|---|
--lint |
告警,提示使用非可移植扩展语法 |
--lint‑old |
提示原始V7‑awk不兼容的代码 |
--traditional |
关闭gawk特有扩展,模拟Bell Labs nawk |
--posix |
严格POSIX模式,禁用所有扩展 |
--re‑interval |
开启正则{m,n}区间量词 |
--source '脚本' |
和‑f配合,内联脚本+外部库文件一起运行 |
示例:
|
|
AWKPATH环境变量
gawk查找‑f指定脚本文件的搜索路径;类似shell的PATH。
如果文件名包含
/(绝对/相对路径),不会走AWKPATH搜索。
gawk扩展正则表达式
表11‑5
| 符号 | 含义 |
|---|---|
\w |
匹配单词字符:字母、数字、下划线 [A‑Za‑z0‑9_] |
\W |
匹配非单词字符:不是字母 / 数字 / 下划线的任意字符 |
\< |
单词开头边界:单词字符的前面那个缝隙位置,匹配:前面不是单词字符,后面是单词字符 的位置。 |
\> |
单词结尾边界:单词字符的后面那个缝隙位置,匹配:前面是单词字符,后面不是单词字符 的位置。 |
\y |
单词边界:等价 \< 或者 \>,开头或者结尾都可以 |
\B |
非单词边界,单词字符和单词字符中间的缝隙;或者非单词和非单词中间缝隙 |
| \` | 字符串(记录)开头位置,等价 ^ |
\' |
字符串(记录)结尾位置,等价 $ |
示例
| 表达式 | 可以匹配 | 不能匹配 | 简要说明 |
|---|---|---|---|
\<away |
away、(away) |
stowaway |
单词开头,away前面不能是单词字符 |
stow\> |
stow、stow. |
stowaway |
单词结尾,stow后面不能是单词字符 |
\yballs?\y |
ball、balls、ball, |
ballroom、baseball |
单词的前后任意一边边界 |
\Brat\B |
crate |
dirty rat |
rat的前后都必须是字母(非单词边界) |
\w |
a、7、_ |
空格 , ! |
单个单词字符 |
\W |
空格 , # |
b 3 _ |
单个非单词字符 |
| \`test | test ok |
aa test ok |
记录开头,同^test |
ok\' |
hi ok |
hi ok!! |
记录结尾,同ok$ |
gawk特有变量
表11‑8
| 变量 | 说明 |
|---|---|
ARGIND |
当前输入文件,在ARGV数组里面的下标索引 |
ERRNO |
getline / close出错时,保存错误描述字符串 |
FIELDWIDTHS |
固定宽度字段,按字符长度切分字段;用于没有分隔符的固定宽度文本 |
IGNORECASE |
非0则正则、字符串匹配忽略大小写;不影响数组下标 |
RT |
RS为正则时,保存实际匹配到的记录分隔符文本 |
FIELDWIDTHS示例
gawk特有函数
表11‑9
| 函数 | 说明 |
|---|---|
gensub(r,s,h,t) |
增强替换;返回新字符串,不修改原内容;h为"g"全局,数字代表替换第N次匹配;t默认$0;支持\1 \2捕获组引用 |
systime() |
返回Unix时间戳,1970‑01‑01 UTC以来秒数 |
strftime(fmt,[ts]) |
把时间戳格式化人类可读日期时间 |
gensub示例:
|
|
sub/gsub会直接修改原字符串;gensub返回新字符串,源字符串不变。
时间示例:
|
|
gawk特殊文件名
/dev/stdin /dev/stdout /dev/stderr /dev/fd/n;还有一批已经废弃的/dev/pid等,改用PROCINFO[]数组。
mawk
Michael Brennan开发,完全兼容POSIX;运行速度快,跨平台,支持DOS。
- 支持通用扩展:
delete array清空数组、FS=““字符拆分、nextfile、RS正则。 - 不支持/dev/stdin,用
"-"代表标准输入。 - 扩展数量少于gawk,追求速度。
商业版本awk
MKS awk(Windows)
运行于Windows;POSIX兼容;新增ord()函数,取字符ASCII码。
tawk(Thompson Automation)
编译器型awk,不是解释器,可以编译生成独立exe;调试器;大量高级扩展。 重要扩展特性:
INIT、BEGINFILE、ENDFILE特殊模式;BEGINFILE文件打开前执行,空文件也触发。- 正则可以加标志:
/pattern/i忽略大小写。 - 真正多维数组
a[1][1](标准awk是模拟多维a[1,1])。 - 数组遍历
for(in)可以可控排序。 FPAT变量:按正则模式定义字段内容,而不是分隔符。RECLEN读取定长二进制记录。- 十六进制字面量
0x10;大量系统调用、目录、文件操作内置函数。
VSAwk
Visual Basic组件,把awk的处理模型移植到VB环境。
第十一章核心速记清单
- 原始V7‑awk:残缺,无
getline、无自定义函数、无in数组判断、无**求幂、不支持三元运算符。写脚本不要假设目标机器是原始awk。 - POSIX‑awk标准能力:是可移植脚本的底线;很多好用特性(
delete arr、fflush()、nextfile、RS正则)属于扩展,不一定所有环境都有。 - 三大免费实现:
- Bell‑Labs nawk:官方原版。
- gawk(Linux默认):扩展最多;
--posix/--traditional切换模式;gensub()、时间函数strftime()、IGNORECASE、FIELDWIDTHS、RT。 - mawk:速度优先,扩展少一点。
- 重要区分:
next:跳过当前一条记录;nextfile:跳过整个输入文件,直接下一个文件(扩展,非POSIX)。
- 特殊文件:
/dev/tty全部awk通用,输出直接到终端,不受shell重定向影响。 - 可移植脚本开发原则:
- 尽量只用POSIX规定语法;
- gawk开发完,打开
gawk --posix做兼容性检查; - 不要依赖
gensub、nextfile、FIELDWIDTHS这类扩展,否则换到其他UNIX会报错。
- tawk是编译器商业版本,有真正多维数组、FPAT、BEGINFILE等大量高级扩展。
小提示:Linux上
awk实际是gawk;FreeBSD/macOS上默认awk接近nawk/mawk,扩展少,做跨平台脚本要格外小心。
文章作者 会写代码的小郎中
上次更新 2011-08-10
许可协议 CC BY-NC-ND 4.0