AWK主要用于文本数据处理,由Afred, Weinberger和Kernighan设计,故名AWK。
AWK的初始版本由AT&T实验室开发,此外,NAWK
是AWK的改进版本,而应用最广泛的当属GAWK
,即GNU AWK
,为Linux内置的默认版本,对AWK和NAWK可以完全兼容。
Awk
的程序结构包括三个区块:
BEGIN {awk-commands}
/pattern/ {awk-commands}
END {awk-commands}
其中awk-commands
表示awk
指令;/pattern/
表示指定的处理模式。
以文本文件test.txt
为例,下面为其内容
1) Amit Physics 80
2) Rahul Maths 90
3) Shyam Biology 87
通过awk
可以逐行打印出这个文本文件,并可以添加表头,方法如下
$ awk 'BEGIN{printf "No\tName\tSub\tMarks\n"}{print}' test.txt
No Name Sub Marks
1) Amit Physics 80
2) Rahul Maths 90
3) Shyam Biology 87
其基本方法为,可用awk
直接调用后面的字符串中所写的脚本命令。其中BEGIN
标识的大括号为开始块,用于打印表头;后面的{print}
为主体块,表示按行打印test.txt
中的内容。
通过$
选列,可实现单行输出,例如只想输出人名,则
awk 'BEGIN{printf "Name\n"}{print $2}' test.txt
Name
Amit
Rahul
Shyam
其中$2
表示第二列。
通过awk -f
命令,可以执行脚本,例如可将同样的功能封装入脚本test.awk
中,
# test.awk文件
BEGIN{
printf "Name\n"
}
{
print $2
}
然后在命令行中调用,其效果与刚刚相同
$ awk -f test.awk test.txt
Name
Amit
Rahul
Shyam
除了可以将处理结果打印在命令行中,awk
也可以将其输出到文本文件,其方法为
print DATA > oFile
print DATA >> oFile
可将DATA
输出到oFile
中,如果oFile
不存在,则先创建该文件。>
为写入模式,若oFile
存在,数据输出前会将oFile
中原有的数据删除;>>
为追加模式,数据将在oFile
结尾写入。
下例将test.txt
打开,并重新存储到new.txt
中
awk '{ print $0 > "./new.txt" }' test.txt
当然也可以交换两列的位置
$ awk '{print $4,$3,$2,$1 > "./new.txt"}' test.txt
$ cat new.txt
80 Physics Amit 1)
90 Maths Rahul 2)
87 Biology Shyam 3)
AWK
可通过管道将一个程序的输出传递给另一个程序,其使用方法为
print items | command
例如下例将hello, world"
传递给tr
。
$ awk 'BEGIN { print "hello, world" | "tr [a-z] [A-Z]" }'
HELLO, WORLD !!!
通过|&
可使用双工管道,进行双向通信
# 文件pipe.awk
BEGIN {
cmd = "tr [a-z] [A-Z]" # 建立双向通信惯导
print "hello, world !!!" |& cmd # 为tr提供输入
close(cmd, "to") # 执行后关闭to进程
cmd |& getline out # 将输出存储到out中
print out; # 打印out
close(cmd); # 关闭cmd
}
执行脚本后可得到
HELLO, WORLD !!!
+, -, *, \, %, ^, ** |
加减乘除、取模、乘方、乘方 |
+=, -=, *=, \=, %=, ^= |
加减乘除、取模、乘方对应的复制符 |
++a, --a, a++, a-- |
前置递增、前置递减、后置递增、后置递减 |
==, !=, <, <=, >, >= |
关系运算符,返回真假 |
`&&, |
awk
也支持三元运算符,例如
$ awk 'BEGIN { a = 10; b = 20; (a > b) ? max = a : max = b; print "Max =", max}'
Max = 20
除了单个值的计算,awk
还提供了适用于其他数据类型的运算符
空格
in
~
;不匹配!~
数组遍历的方法为:
BEGIN {
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
for (i in arr)
printf "arr[%d] = %d\t", i, arr[i]
print "\n"
}
调用结果为:
awk -f test.awk
arr[0] = 1 arr[1] = 2 arr[2] = 3
编程语言的流程控制,主要包括判断和循环。
其判断语句就是if...else if...else
的结构:
$ awk 'BEGIN{num=10; if(num%2==0){printf "%d is even\n", num }else{printf "%d is odd"}}'
10 is even
循环在前面的例子也出现过,包括for
循环、while
循环以及do{}while()
,其逻辑与C语言极度相似,故只列一例不做详述。
$ awk 'BEGIN { for (i = 1; i <= 5; ++i) printf "%d\t",i }'
1 2 3 4 5
$ awk 'BEGIN{ i=1; while(i<5){printf "%d\t", i; i++}}'
1 2 3 4
$ awk 'BEGIN{ i=1; do{printf "%d\t", i++}while(i<5)}'
1 2 3 4
在循环中可以通过break
和continue
来结束或跳过本层循环,这也同样与C语言雷同。此外,awk
还有一个关键字exit
,类似于return 0
,可以跳出当前程序。
在awk
中封装函数用关键字function
,例如
# 文件 fcunTest.awk
function fac(n){
if(n>1)
return n*fac(n-1)
else
return 1
}
BEGIN{
printf "5+1=%d", fac(5)
}
这是个递归求阶乘的函数,调用结果为
$ awk -f funcTest.awk
fac(5)= 120
AWK 提供了一些内置变量,列表如下
变量 | 说明 | 默认值 |
---|---|---|
ARGC |
表示在命令行提供的参数的个数 | |
ARGV |
命令行输入的参数数组 | 索引从0开始 |
CONVFMT |
数据转换为字符串的格式 | %.6g |
OFMT |
数值输出格式 | %.6g |
ENVIRON |
环境变量数组 | |
FILENAME * |
当前文件名称 | |
FS |
输入列之间的分隔符 | 空格 |
NF |
当前输入记录中域的数量 | |
NR |
当前记录的数量 | |
FNR |
当前文件的NR | |
OFS |
输出列之间的分割符 | 空格 |
ORS |
行间分割符 | 换行符 |
RLENGTH |
match 匹配字符串长度 |
|
RS |
输入行的分割符 | 换行符 |
RSTART |
match匹配字符串的首字符的位置 | |
SUBSEP |
数组下标的分割行符 | \03 |
$0 |
整个输入记录 | |
$n |
当前输入的第n列 |
* 表示开始块中未定义
以ARGV
和ARGC
为例,可演示一下如何查看这些默认变量
awk 'BEGIN { for (i = 0; i < ARGC - 1; ++i)
{ printf "ARGV[%d] = %s\t", i, ARGV[i] }
}' a b c d
ARGV[0] = awk ARGV[1] = a ARGV[2] = b ARGV[3] = c
此外,GNU AWK
还提供了其他几个内置变量
ARGIND |
正在处理的ARGV索引 |
ERRNO |
失败信息 |
FIELDWIDTHS |
列宽 |
IGNORECASE |
设置后大小写不敏感 |
TEXTDOMAIN |
AWK程序当前文本域 |
BINMODE
:即二进制模式,用于非 POSIX 系统。 数值1、2、3分别指定输入文件、输出文件或所有文件;字符串r
或w
分别指定输入或输出文件使用二进制模式;rw
或wr
指定所有文件使用二进制模式。
LINT
:提供了在GAWK
程序中动态控制--lint
选项的一种途径。此变量设置后,GAWK会输出lint
警告信息。如果给此变量赋予字符值fatal
,lint 的所有警告信息将会变了致命错误信息(fatal errors)输出,和–lint=fatal 效果一样。
and, or, compl, xor |
按位求与、或、非、异或 |
lshift, rshift |
左移位、右移位 |
cos(x), sin(x) |
cos x , sin x \cos x, \sin x cosx,sinx |
exp(x), log(x), sqrt(x) |
exp x , ln x , x \exp x, \ln x, \sqrt x expx,lnx,x |
atan2(y,x) |
arctan y x \arctan\frac{y}{x} arctanxy |
int(x) |
取整 |
rand(), srand(n) |
返回区间 ( 0 , 1 ) (0,1) (0,1)的一个随机数 后者根据随机数种子n来生成 |
基础功能 | ||
---|---|---|
asort(arr,[, d [,how] ]) |
对数组arr的值进行字符排序 | |
asorti(arr,[, d [,how] ]) |
对数组arr的索引进行字符排序 | |
gsub(a, b [, tar]) |
将tar 中的子串a 替换为b ,tar 默认$0 |
|
index(str,sub) |
返回sub 在str 的位置;若不存在则返回0 |
|
length(str) |
返回字符串长度 | |
strtonum(str) |
将str 转为数值 [ 1 ] ^{[1]} [1] |
|
tolower(str) |
将str 转换为小写格式然后返回 [ 1 ] ^{[1]} [1] |
|
toupper(str) |
将str 转换为大写格式然后返回 [ 1 ] ^{[1]} [1] |
|
substr(str, st, L) |
返回str 中从第st 个字符开始长度为L 的子串 |
0
开始,则转为八进制数;如以0x
或0X
开始,则当作十六进制数;否则当作浮点数。tolower
和toupper
并不会改变输入字符串str
本身。与正则表达式相关的功能 | |
---|---|
match(str, regex) |
返回在str 中与regex 匹配的子串的位。 |
sub(regex,sub,str) |
将str 首次出现的与regex 匹配的子串替换为sub str 默认为$0 |
split(str, arr,regex) |
使用regex 分割str ,输出给arr |
其中regex
均表示正则表达式;match
返回的字符串为匹配的最长、最左侧的字符串,如果匹配失败,返回0。
所谓正则表达式,就是通过匹配符来替代特定文字的方法,其常用的匹配字符如下
匹配字符 | |
---|---|
. |
除了行结束字符的所有字符 |
^ |
匹配一行的开始 |
$ |
匹配一行的结束 |
[] |
匹配方括号中的任意字符 |
[^] |
匹配除了[^ 和] 中间的其他字符 |
? |
其前面的字符不出现或出现一次 |
* |
其前面的字符不出现或出现多次 |
+ |
其前面的字符出现一次或多次 |
sprintf(format,expr-list)
按指定格式(format)将参数列表 expr-list 构造成字符串然后返回。
systime
返回从 Epoch 以来到当前时间的秒数(在POSIX系统上,Epoch 为1970-01-01 00:00:00 UTC)。
mktime(dataspec)
将字符串dataspec
转换为与systime
风格的时间戳,dataspec
字符串的格式为 YYYY MM DD HH MM SS。
strftime([format [, timestamp[, utc-flag]]])
根据 format 指定的格式将时间戳 timestamp 格式化。
日期格式说明如下:
SN | 描述 | SN | 描述 |
---|---|---|---|
%a | 星期缩写 | %A | 星期全称 |
%b | 月份缩写 | %B | 月份全称 |
%c | 本地日期与时间 | %C | 世纪数 |
%d | 十进制日期(01-31) | %D | 等价于 %m/%d/%y. |
%e | 日期,如果只有一位数字则用空格补齐 | ||
%F | 等价于 %Y-%m-%d | ||
%G | 标准周所在年份的全称 | %g | 标准周所在的年份模除100 |
%h | 等价于 %b | ||
%H | 24小时格式的小时[00-23] | %I | 12小时格式的小时[00-12] |
%j | 一年中的第几天[001-366] | ||
%m | 月份[01-12] | %M | 分钟数[00-59] |
%n | 换行符 (ASCII LF) | ||
%p | 十二进制表示法(AM/PM) | ||
%r | 等价于 %I:%M:%S %p | %R | 等价于 %H:%M。 |
%S | 时间的秒数值(00-60) | ||
%t | 制表符 (tab) | %T | 等价于 %H:%M:%S。 |
%u | 以数字表示的星期(1-7),1 表示星期一。 | ||
%U | 一年中星期序号 | %V | 一年中星期序号 |
%w | 星期[0-6],0表示星期日 | %W | 一年中星期序号s |
%x | 本地日期表示 | %X | 本地时间表示 |
%y | 年份模除100 | %Y | 十进制表示的完整年份。 |
%z | 时区,表示格式为+HHMM | ||
%Z | 时区名称或缩写,如果时区待定则无输出。 |
其中,%U
以周日为一周开始;%V, %W
以周一作为一周开始;
%z
的表示格式为+HHMM(例如,格式要求生成的 RFC 822或者 RFC 1036 时间头)
close(expr) |
关闭管道的文件 |
delete |
从数组中删除元素 |
exit |
终止脚本执行 |
flush |
刷新打开文件或管道的缓冲区 |
getline |
读入下一行 |
next |
停止处理当前记录,并且进入到下一条记录的处理过程 |
nextfile |
停止处理当前文件,从下一个文件第一个记录开始处理。 |
system |
执行特定的命令,返回其退出状态,0表示成功,否则表示失败 |