gawk 是 Unix 中的原始 awk 程序的 GUN 版本。
$0 代表整个文本行;
$1 代表第一个数据字段;
….
# gawk 会从 STDIN 接收数据,输入任何值,都会打印 hello world$ gawk '{print "hello world"}'# 从文件中获取输入,打印第一列$ gawk '{print $1}' data.txt# 多个命令$ echo "My name is Rich" | gawk '{$4="xiaocan"; print $0}'My name is xiaocan
BEGIN
# 在处理数据前运行脚本使用 BEGIN$ gawk 'BEGIN {print "hello world"}'hello world$ gawk 'BEGIN {print "hello world"}> {print $0}' data4.txthello worldThis is a test of the test script;This is the second test of the test script;
END
# 在处理数据后运行脚本使用 END$ gawk 'BEGIN {print "hello world"}> {print $0}> END {print "End of file"}' data4.txthello worldThis is a test of the test script;This is the second test of the test script;End of file
分隔符
每个字段通过分隔符划分,默认是任意的空白字符。可以指定其它的。
# 指定分隔符$ gawk -F: '{print $1}' /etc/passwd# 可以使用 FS 变量定义字段分隔符$ gawk 'BEGIN {print "This PC user list:"; FS=":"}> {print $1}> END {print "all done"}' /etc/passwd
指定文件 -f
$ cat script2.gawk{print $1 "'s home directory is " $6}# 指定命令文件$ gawk -F: -f script2.gawk /etc/passwd
自定义变量
变量区分大小写。
# 注意,不用使用 $ 引用$ gawk '> BEGIN{> testing="This is a test"> print testing> }'This is a test$ gawk 'BEGIN{x=4;x=x*2+3;print x}'11# 文件中使用变量和多行$ cat script3.gawk{text = "'s home directory is "print $1 text $6}$ gawk -F: -f script3.gawk /etc/passwdroot's home directory is /rootdaemon's home directory is /usr/sbinbin's home directory is /binsys's home directory is /dev...
在命令行上给变量赋值
$ cat script1BEGIN {FS=","}{print $n}$ gawk -f script1 n=3 data1data13data23data33$ cat script2BEGIN {print "The starting value is",n; FS=","}{print $n}# 变量在 BEGIN 中不能使用$ gawk -f script2 n=3 data1The starting value isdata13data23data33# 使用 -v 参数,就可以在 BEGIN 中使用变量$ gawk -v n=3 -f script2 data1The starting value is 3data13data23data33
内建变量
字段分隔符和记录分隔符变量
| 变量 | 描述 |
|---|---|
| FIELDWIDTHS | 由空格分隔的一列数字,定义了每个数据字段确切宽度 |
| FS | 输入字段分隔符,默认为空格 |
| RS | 输入记录分隔符,默认为换行符 |
| OFS | 输出字段分隔符,默认为空格 |
| ORS | 输出记录分隔符,默认为换行符 |
$ cat data1data11,data12,data13,data14,data15data21,data22,data23,data24,data25data31,data32,data33,data34,data35$ gawk 'BEGIN{FS=","} {print $1,$2,$3}' data1data11 data12 data13data21 data22 data23data31 data32 data33# 指定输出字段分隔符$ gawk 'BEGIN{FS=","; OFS="--"} {print $1,$2,$3}' data1data11--data12--data13data21--data22--data23data31--data32--data33$ cat data1b1005.23424234.37115-2.3453450.000582.23442133.23# 使用 FIELDWIDTHS 分隔$ gawk 'BEGIN{FIELDWIDTHS="3 5 2 6"} {print $1,$2,$3,$4}' data1b100 5.234 24 234.37115 -2.34 53 450.00058 2.234 42 133.23
可以把 RS 变量设制成空字符串,然后在数据记录间留一个空白行。gawk 会把每个空白行当作一个记录分隔符。
$ cat data2xiaocan123456789zhangsan123456789xxxxx2342424234$ gawk 'BEGIN{RS="";FS="\n"} {print $1,$2}' data2xiaocan 123456789zhangsan 123456789xxxxx 2342424234
数据变量
ARGC 当前命令行参数个数
ARGV 包含命令行参数的数组
# 注意,程序脚本不会当作命令行参数的一部分$ gawk 'BEGIN{print ARGC,ARGV[1]}' data12 data1
ENVIRON 当前 shell 环境变量及其值组成的关联数组,可以用它获取任意的环境变量
$ gawk '> BEGIN{> print ENVIRON["HOME"]> print ENVIRON["PATH"]> }'/home/xiaocan/home/xiaocan/gems/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
NF 字段总数,可以用它获取最后一个字段
$ gawk 'BEGIN{FS=":"; OFS=":"} {print $1,$NF}' /etc/passwdroot:/bin/bashdaemon:/usr/sbin/nologinbin:/usr/sbin/nologinsys:/usr/sbin/nologinsync:/bin/syncgames:/usr/sbin/nologinman:/usr/sbin/nologin...
NR 当前处理的所有文件已处理的行数,同时处理多个文件会累加。
FNR 当前处理的文件已处理的行数
$ gawk '> BEGIN {FS=","}> {print $1, "FNR="FNR, "NR="NR}> END {print "There were",NR,"records processed"}' data1 data1data11 FNR=1 NR=1data21 FNR=2 NR=2data31 FNR=3 NR=3data11 FNR=1 NR=4data21 FNR=2 NR=5data31 FNR=3 NR=6There were 6 records processed
处理数组
gawk 里面的数组更像是散列表:
$ gawk 'BEGIN{> capital["China"] = "Beijing"> print capital["China"]> }'Beijing$ gawk 'BEGIN{> var[1] = 2> var[2] = 3> print var[1] + var[2]> }'5
使用 for 遍历数组:
$ gawk 'BEGIN{> var["a"] = 1> var["b"] = 2> var["c"] = 3> for (test in var)> {> print "Index:",test," - value:",var[test]> }> }'Index: a - value: 1Index: b - value: 2Index: c - value: 3
数据数组变量:
$ gawk 'BEGIN{> var["a"] = 1> var["b"] = 2> var["c"] = 3> delete var["c"]> print var["c"]> }'
使用模式
正则表达式
正则表达式必须出现在它要控制的程序脚本的左花括号前。
# 过滤并打印$ echo "This is a test" | gawk "/test/{print $0}"
匹配操作符
它可以将正则表达式限定在记录中的特定数据字段。比如 $1 ~ /^data/ ,匹配第一个字段以 data 开头的记录。
$ cat data1data11,data12,data13,data14,data15data21,data22,data23,data24,data25data31,data32,data33,data34,data35$ gawk 'BEGIN{FS=","} $2 ~ /^data2/{print $0}' data1data21,data22,data23,data24,data25
可以用使用 ! 来排除正则表达式的匹配:
$ gawk 'BEGIN{FS=":"} $1 !~ /root/{print $1,$NF}' /etc/passwddaemon /usr/sbin/nologinbin /usr/sbin/nologinsys /usr/sbin/nologin
数学表达式
$ gawk -F: '$4==0 {print $1}' /etc/passwdroot
支持的数据表达式有:
x == y
x <= y
x < y
x >= y
x > y
也可以的文本数据使用表达式:
$ gawk -F: '$1 == "root" {print $0}' /etc/passwdroot:x:0:0:root:/root:/bin/bash
结构化命令
if 语句
$ cat data41051350346$ gawk '{if($1 > 40) print $1}' data450# if-else$ gawk '{> if($1>20)> {> x = $1 * 2;> }else{> x = $1 / 2> }> print x> }' data452.56.5100683# 单行命令$ gawk '{if($1>20)print $1*2; else print $1/2}' data452.56.5100683
while 语句
$ cat data5130 120 135110 110 130160 170 180220 220 225$ gawk '{total = 0i = 1while (i < 4){total += $ii++}print total, total/3}' data5385 128.333350 116.667510 170665 221.667
还可以使用 break 和 continue 语句。
do while 语句
$ gawk '{> total=0> i = 1> do{> total+=$i> i++> } while(i<4)> print total, total/3> }' data5385 128.333350 116.667510 170665 221.667
for 语句
$ gawk '{> total = 0> for (i=1;i<4;i++)> {> total+=$i> }> avg = total/3> print "Average:", avg> }' data5Average: 128.333Average: 116.667Average: 170Average: 221.667
格式化打印
使用 printf 格式化打印。格式化的格式是:%[modifier]control-letter
Control-letter 控制字母有:
e 用科学记数法显示一个数
d 显示一个整数值
f 显示一个浮点数
s 显示文本字符串
…
modifier 修饰符有:
width:指定长度,如果小于这个值,会将文本右对齐,用空格进行填充;
prec:数字值,指定浮点数中小数点后面位数
减号:使用左对齐
$ gawk 'BEGIN{> x = 10 * 100> printf "The answer is: %e\n",x> }'The answer is: 1.000000e+03$ gawk 'BEGIN{FS=","} {printf "%s ", $1} END{printf "\n"}' data1data11 data21 data31$ gawk '{> total=0> for (i=0;i<4;i++)> {> total+=$i> }> avg=total/3> printf "Average: %5.1f\n",avg> }' data5Average: 128.3Average: 116.7Average: 170.0Average: 221.7
内建函数
数学函数
exp(x) x的指数函数
int(x) x的整数部分
rand() 生成0到1 之间的随机浮点数
sqrt() x的平方根
比如 x=int(10 * rand()) 生成 0 到 10 的随机数。
gawk 还支持一些按位操作数据的函数。
字符串函数
length([s]) 返回字符串 s 的长度,如果没有指定的话,返回 $0 的长度。
tolower(s) 字符串转小写
toupper(s) 字符串转大写
$ gawk 'BEGIN{x="testing"; print toupper(x); print length(x)}'TESTING7
时间函数
systime() 返回当前时间
自定义函数
函数需要在所有代码块之前定义:
$ gawk '> function myprint()> {> printf "%-16s - %s\n", $1, $2> }> BEGIN{FS="\n"; RS=""}> {> myprint()> }' data2xiaocan - 123456789zhangsan - 123456789xxxxx - 2342424234
将函数保存到其它文件中:
$ cat funclibfunction myprint(){printf "%-16s - %s\n", $1, $2}$ cat script4BEGIN{ FS="\n"; RS=""}{myprint()}$ gawk -f funclib -f script4 data2xiaocan - 123456789zhangsan - 123456789xxxxx - 2342424234
示例
下面的文件中,第一列是项目名称,第二列是开发者,后面是每天的代码提交量。我们来统计一下每个开发者在所有项目中的代码量。
$ cat git-code.txtproject-one,zhangsan,80,12,56,23,12project-one,lisi,12,23,45,23,120project-two,wangwu,234,23,35,77,34project-one,zhangsan,23,34,32,67,34
下面是统计的脚本:
$ cat code.sh#!/bin/bashfor author in $(gawk -F, '{print $2}' git-code.txt | sort | uniq)dogawk -v author=$author 'BEGIN{FS=","; total=0}{if($2 == author){total+= $3 + $4 + $5 + $6 + $7}}END {print "Total code for", author, "is", total}' git-code.txtdone# 运行结果$ sh code.shTotal code for lisi is 223Total code for wangwu is 403Total code for zhangsan is 373
