gawk 是 awk 的 GUN 版
===========================================
是一种《模式扫描和处理》语言。它搜索一个或多个文件,查看这些文件中是否存在匹配指定模式的记录。发现匹配后,通过执行动作来处理那一行。
语法:
gawk 参数 命令 待处理文件列表
参数
------------------------------------------
-F fs 将 fs 作为文件列表的分隔符
-f abc 从文件 abc 中读取 awd 命令。和 sed 的 -f 一样
-v var=value 将 value 赋给变量 var
gawk 是 UNIX awk 的 GUN 版。为了方便,许多 Linux 系统将 /bin/awk 链接到
/bin/gawk
命令
------------------------------------------
模式 {动作}
和 sed 一样. gawk
也提供一个正则表达式,来选择需要处理的行。如果不提供表达式,则会处理所有行。表达式后是要处理的动作,如果不提供动作。gawk
会把行内容输出到标准输出。
表达式:
------------------------------------------
包括在两个斜杠中: /表达式/
~ 操作符用于测试某个或者变量是否匹配正则表达式。
!~用于测试不匹配。
数值和字符串的比较还可以用:
=, >
还可以用 ||, && 来比较。
另外还包括两个 gawk 特殊的命令: BEGIN, END.
gawk 开始处理之前,执行 BEGIN 模式关联的活动,处理完所有的动作后执行 END 关联的动作。
逗号(,)是范围操作符。如果在一个 gawk 程序行上用逗号将两个模式隔开,gawk 先匹配第 1
个模式,范围是从第一行,到匹配第 2 个模式的那行。若没有匹配第 2 个模式的文本行,gawk
将选取直到输入文件最后的一行。然后再匹配第 2 个模式。完成后,它将再次查找第 1 个模式,如此反复。
动作:
------------------------------------------
匹配到符合条件的行后,gawk
就会对这些行进行相应的动作处理。动作都是包括在大括号{}中的。若没有添加,会默认给它一个{print}动作,即把所匹配的行打印到标准输出上。可以将
print 的内容输出到其它文本中,如:>, >>, |, |&
若是想执行多个动作,可以用分号将多个动作隔开。
gawk 不处理以 # 号开关的程序行。所以,可以在 gawk 命令文件中用 # 添加注释。
gawk 中我们可以自己声明变量,数值变量默认值是 0,字符串为空。同时,gawk
还有类似全局变量。我们可以直接访问:
$0 当前记录
$1-$n 当前记录中的字段
FILENAME 当前输入文件名, 若值为 null 表示是标准输入
FS 输入字段分隔符(查看前面的命令参数)
NF 当前记录的字段数目
NR 当前记录的记录编号
OFS 输出字段分隔符, 默认是空格
ORS 输出记录分隔符, 默认是换行符
RS 输入记录分隔符, 默认是换行符
函数:
------------------------------------------
对数字和字符串的一些函数:
length(str) 返回 str 中的字符个数;如果没有传参数,则返回当前记录中的字符个数
int(num) 返回 num 的整数部分
index(str1, str2) 返回 str2 在 str1 中的位置。如果 str 不存在, 返回 0
split(str,arr,del) 用 del 作为定界符,切割 str 成数组.返回数组的长度
sprintf(fmt,args) 格式化 args 并返回格式化后的字符串
substr(str,pos,len) 返回 str 中从 pos 开始,长度为 len 的字符串
tolower(str) 将 str 中所有大写字母变成小写, 然后返回
toupper(str) 将 str 中所有小写字母变成大写, 然后返回
算术操作符
------------------------------------------
*, /, %, +, -, =, ++, --, +=, -=, *=, /=, %=
关联数组
------------------------------------------
和 PHP 的数组一样, gawk 的数组可以使用字符串作为索引。使用方式也类似:
array[key]=value;
for(loop in array)...
printf
------------------------------------------
printf 用来代替 print, 格式化 gawk 的输出。语法如下:
printf "格式", arg1, arg2, ..., argn
"格式" 决定了 printf 如何格式化后面的参数。这些参数可以是变量,也可以是其他表达式。格式中,\n 表示换行;\t
表示 tab 。
一个 arg 就是对应一个格式。格式的语法是:
%[-][x[.y]]conv
叵带上 - 参数,表示参数左对齐,x 表示最小字段宽度,.y 表示数字中小数点右边的位数。conv
表示数值转换的类型,类型有:
d 十进制的数字
e 指数表示
f 浮点数
g 使用 f 或 e 中较短的那个
o 无符号八进制
s 字符串
x 无符号 16 进制
结构控制
------------------------------------------
if..else
如:
if($5 <= 5000){
print $0
}
while
如:
while(n <= 5){
print n
n++
}
for
for(i=1;i<=5;i++){
print i
}
for(loop in array){
print loop
}
break: 退出 for 或 while
continue: 跳出本次循环,进入下一个循环
测试
===================================================
建立测试文件: cars.txt
内容是:
[root@localhost wwwlogs]# cat cars.txt
plym fury 1970 73 2500
chevy malibu 1999 60 3000
ford mustang 1965 45 10000
volvo s80 1998 102 9850
ford thundbd 2003 15 10500
chevy malibu 2000 50 3500
bmw 3251 1985 115 450
honda accord 2001 30 6000
ford taurus 2004 10 17000
toyota rav4 2002 180 750
chevy impata 1985 85 1550
ford explor 2003 25 9500
简单命令--不写模式
----------------------------------------
[root@localhost wwwlogs]# gawk '{print}'
cars.txt
plym fury 1970 73 2500
chevy malibu 1999 60 3000
ford mustang 1965 45 10000
volvo s80 1998 102 9850
ford thundbd 2003 15 10500
chevy malibu 2000 50 3500
bmw 3251 1985 115 450
honda accord 2001 30 6000
ford taurus 2004 10 17000
toyota rav4 2002 180 750
chevy impata 1985 85 1550
ford explor 2003 25 9500
简单动作--不写动作
----------------------------------------
[root@localhost wwwlogs]# gawk '/chevy/'
cars.txt
chevy malibu 1999 60 3000
chevy malibu 2000 50 3500
chevy impata 1985 85 1550
不写动作时, gawk 会默认添加一个 print 动作.
注意: gawk 中可以不用单引号将命令包起来.但包起来要好一些.万一命令里有特殊字符呢.
字段
----------------------------------------
前面介绍过,在 gawk 中,用 $0-$n 表示第 n 个字段.
[root@localhost wwwlogs]# gawk '{print $3, $1}'
cars.txt
1970 plym
1999 chevy
1965 ford
1998 volvo
2003 ford
2000 chevy
1985 bmw
2001 honda
2004 ford
2002 toyota
1985 chevy
2003 ford
上面的命令处理所有的行, 且打印第 3 个字段, 以及第 1 个字段. 且中间加一个空格.
注: 多个字段之间用逗号分隔
延伸一下:
[root@localhost wwwlogs]# gawk '/chevy/ {print $3, $1}'
cars.txt
1999 chevy
2000 chevy
1985 chevy
[root@localhost wwwlogs]# gawk '/h/'
cars.txt
chevy malibu 1999 60 3000
ford thundbd 2003 15 10500
chevy malibu 2000 50 3500
honda accord 2001 30 6000
chevy impata 1985 85 1550
~ 是匹配操作符.
----------------------------------------
用来指定要匹配的模式在哪个字段中:
[root@localhost wwwlogs]# gawk '$1 ~ /h/'
cars.txt
chevy malibu 1999 60 3000
chevy malibu 2000 50 3500
honda accord 2001 30 6000
chevy impata 1985 85 1550
上面是在第一个字段中查找有 h 的行.
在模式中加上复制点的正则:
^ 它指定必须在行首进行匹配:
----------------------------------------
[root@localhost wwwlogs]# gawk '$1 ~ /^h/'
cars.txt
honda accord 2001 30 6000
中括号指定在括号中的内容中选择
----------------------------------------
[root@localhost wwwlogs]# gawk '$2 ~ /^[tm]/ {print $3, $2,
"$"$5}' cars.txt
1999 malibu $3000
1965 mustang $10000
2003 thundbd $10500
2000 malibu $3500
2004 taurus $17000
注意: $
符号在模式中,若后面紧跟一个数字,表示第几个字段。但它在正则中还表示行尾:
----------------------------------------
[root@localhost wwwlogs]# gawk '$3 ~ /5$/ {print $3, $1,
"$"$5}' cars.txt
1965 ford $10000
1985 bmw $450
1985 chevy $1550
上面命令找出了第三列以 5 为结尾的行
模式中还可以加入其它操作符.来进行逻辑比较:
----------------------------------------
[root@localhost wwwlogs]# gawk '$3 == 1985 {print $3, $1,
"$"$5}' cars.txt
1985 bmw $450
1985 chevy $1550
[root@localhost wwwlogs]# gawk '$5 <= 3000 {print $3, $1,
"$"$5}' cars.txt
1970 plym $2500
1999 chevy $3000
1985 bmw $450
2002 toyota $750
1985 chevy $1550
另外,数值的比较和字符串的比较不一样.字符串是按 ascii 来比较的
看下例:
[root@localhost wwwlogs]# gawk '"2000" <= $5 && $5
< "9000" {print $3, $1, "$"$5}' cars.txt
1970 plym $2500
1999 chevy $3000
2000 chevy $3500
1985 bmw $450
2001 honda $6000
2002 toyota $750
[root@localhost wwwlogs]# gawk '2000 <= $5 && $5
< 9000 {print $3, $1, "$"$5}' cars.txt
1970 plym $2500
1999 chevy $3000
2000 chevy $3500
2001 honda $6000
范围操作符: ,
----------------------------------------
[root@localhost wwwlogs]# gawk '/volvo/ , /bmw/'
cars.txt
volvo s80 1998 102 9850
ford thundbd 2003 15 10500
chevy malibu 2000 50 3500
bmw 3251 1985 115 450
范围操作符前面已经介绍过.
在本例中详细进行解读:
上面示例选中从包含 volvo 的行开始,到包含 bmw 的行结束之间的所有文本行。
再看一例:
[root@localhost wwwlogs]# gawk '/chevy/ , /ford/'
cars.txt
chevy malibu 1999 60 3000
ford mustang 1965 45 10000
chevy malibu 2000 50 3500
bmw 3251 1985 115 450
honda accord 2001 30 6000
ford taurus 2004 10 17000
chevy impata 1985 85 1550
ford explor 2003 25 9500
注意,原始文件如下:
plym fury 1970 73 2500
chevy malibu 1999 60 3000
ford mustang 1965 45 10000
volvo s80 1998 102 9850
ford thundbd 2003 15 10500
chevy malibu 2000 50 3500
bmw 3251 1985 115 450
honda accord 2001 30 6000
ford taurus 2004 10 17000
toyota rav4 2002 180 750
chevy impata 1985 85 1550
ford explor 2003 25 9500
查找过程是:
1.先找 chevy 的行, 找出了第 2 行, 再找 ford, 找出了第 3 行.这样就选择了第 2, 3
行
2.再找 chevy 的行, 找出了第 6 行, 再找 ford, 找出了第 9 行.这样就选择了 6, 7, 8, 9
行
3.再找 chevy 的行, 找出了第 11 行, 再找 ford, 找出了第 12 行.这样就选择了 11, 12
行
4...如此重复上面的查找.
第 5 行被过滤掉了.因为第二次查找是从第 6 行开始的.
============================================================
基本用法结束
============================================================
若 gawk 命令较长.可以将命令放在外部文件中, 在命令中通过 -f filename 来引入.
建立命令文件 pr_header 内容如下:
[root@localhost wwwlogs]# cat
pr_header
BEGIN {print "Make Model Year Miles Price"}
{print}
命令第一行输出一串字符串.第二行是一个缺少模式的命令.它会输出所有的行.
执行结果:
[root@localhost wwwlogs]# gawk -f pr_header
cars.txt
Make Model Year Miles Price
plym fury 1970 73 2500
chevy malibu 1999 60 3000
ford mustang 1965 45 10000
volvo s80 1998 102 9850
ford thundbd 2003 15 10500
chevy malibu 2000 50 3500
bmw 3251 1985 115 450
honda accord 2001 30 6000
ford taurus 2004 10 17000
toyota rav4 2002 180 750
chevy impata 1985 85 1550
ford explor 2003 25 9500
输出了上面一串表头, 然后输出文件中的所有内容
注意: BEGIN{} 中的内容会在 gawk 处理行之前就执行.而 END{} 会在处理完后再执行.
再看另一例:
[root@localhost wwwlogs]# cat
pr_header2
BEGIN {
print "Make Model Year Miles Price"
print "---------------------------------------"
}
{print}
[root@localhost wwwlogs]# gawk -f pr_header2
cars.txt
Make Model Year Miles Price
---------------------------------------
plym fury 1970 73 2500
chevy malibu 1999 60 3000
ford mustang 1965 45 10000
volvo s80 1998 102 9850
ford thundbd 2003 15 10500
chevy malibu 2000 50 3500
bmw 3251 1985 115 450
honda accord 2001 30 6000
ford taurus 2004 10 17000
toyota rav4 2002 180 750
chevy impata 1985 85 1550
ford explor 2003 25 9500
length 函数
---------------------------------------
[root@localhost wwwlogs]# gawk '{print length, $0}' cars.txt |
sort -n
22 bmw 3251 1985 115 450
23 plym fury 1970 73 2500
24 volvo s80 1998 102 9850
25 ford explor 2003 25 9500
25 toyota rav4 2002 180 750
26 chevy impata 1985 85 1550
26 chevy malibu 1999 60 3000
26 chevy malibu 2000 50 3500
26 ford taurus 2004 10 17000
26 honda accord 2001 30 6000
27 ford mustang 1965 45 10000
27 ford thundbd 2003 15 10500
上例中使用了不传参数的 length 函数, 它会返回当前行的字符个数,包含字段分隔符.$0 表示当前行.输出后, gawk
将结果发送到 sort , -n 参数会根据文本行的长度进行排序.
NR
---------------------------------------
[root@localhost wwwlogs]# gawk 'length > 24 {print NR, $3,
$1, "$"$5}' cars.txt
2 1999 chevy $3000
3 1965 ford $10000
5 2003 ford $10500
6 2000 chevy $3500
8 2001 honda $6000
9 2004 ford $17000
10 2002 toyota $750
11 1985 chevy $1550
12 2003 ford $9500
另一例:
[root@localhost wwwlogs]# gawk 'NR == 2, NR == 4'
cars.txt
chevy malibu 1999 60 3000
ford mustang 1965 45 10000
volvo s80 1998 102 9850
if
---------------------------------------
[root@localhost wwwlogs]# cat
separ_demo
{
if($1 ~ /ply/) $1 = "Plymouth"
if($1 ~ /chev/) $1 = "Chevrolet"
}
[root@localhost wwwlogs]# gawk -f separ_demo
cars.txt
Plymouth fury 1970 73 2500
Chevrolet malibu 1999 60 3000
ford mustang 1965 45 10000
volvo s80 1998 102 9850
ford thundbd 2003 15 10500
Chevrolet malibu 2000 50 3500
bmw 3251 1985 115 450
honda accord 2001 30 6000
ford taurus 2004 10 17000
toyota rav4 2002 180 750
Chevrolet impata 1985 85 1550
ford explor 2003 25 9500
它的功能是: 如果第一列中符合模式 ply, 就将第一列改成 Plymouth, 若符合 chev, 就改为:
Chevrolet
独立脚本
---------------------------------------
每次执行命令时, 我们都要输入 gawk 然后加参数命令之类的,较麻烦.下面有个简单办法:
建立一个命令文件 separ_demo2 内容如下:
[root@localhost wwwlogs]# cat separ_demo2
#!/bin/gawk -f
{
if($1 ~ /ply/) $1 = "Plymouth"
if($1 ~ /chev/) $1 = "Chevrolet"
}
给命令文件加上执行权限:
chmod +x separ_demo2
[root@localhost wwwlogs]# ./separ_demo2
cars.txt
Plymouth fury 1970 73 2500
Chevrolet malibu 1999 60 3000
ford mustang 1965 45 10000
volvo s80 1998 102 9850
ford thundbd 2003 15 10500
Chevrolet malibu 2000 50 3500
bmw 3251 1985 115 450
honda accord 2001 30 6000
ford taurus 2004 10 17000
toyota rav4 2002 180 750
Chevrolet impata 1985 85 1550
ford explor 2003 25 9500
OFS
---------------------------------------
通过修改 OFS 可以将输出字段的分隔符用指定字符替换:
printf
---------------------------------------
[root@localhost wwwlogs]# cat
printf_demo
BEGIN{
print " Miles"
print "Make Model Year (000) price"
"----------------------------------------------------------------------------"
}
{
if($1 ~ /ply/) $1 = "Plymouth"
if($1 ~ /chev/) $1 = "Chevrolet"
printf "%-10s %-8s - ] $%-8.2f\n",$1,$2,$3,$4,$5
}
[root@localhost wwwlogs]# gawk -f printf_demo
cars.txt
Miles
Make Model Year (000) price
----------------------------------------------------------------------------
Plymouth fury 1970 73
$2500.00
Chevrolet malibu 1999 60
$3000.00
ford mustang 1965 45 $10000.00
volvo s80
1998 102
$9850.00
ford thundbd 2003 15 $10500.00
Chevrolet malibu 2000 50
$3500.00
bmw 3251 1985
115 $450.00
honda accord
2001 30
$6000.00
ford taurus 2004 10
$17000.00
toyota rav4
2002 180
$750.00
Chevrolet impata 1985 85
$1550.00
ford explor 2003 25
$9500.00
重定向输出
---------------------------------------
下面文件输出两个文件.
[root@localhost wwwlogs]# cat
redirect_out
/chevy/ {print > "chevfile"}
/ford/ {print > "fordfile"}
END {print "done."}
[root@localhost wwwlogs]# gawk -f redirect_out
cars.txt
done.
[root@localhost wwwlogs]# cat chevfile
chevy malibu 1999 60 3000
chevy malibu 2000 50 3500
chevy impata 1985 85 1550