gawk程序的简单使用

一、gawk程序的基本格式

gawk options program file

(1)常用的选项如下:

-F fs             指定行中划分数据字段的字段分隔符
-f file           从指定文件中读取程序
-v var=value      定义gawk程序中的一个变量及其默认值
-mf N             指定要处理的数据文件中的最大字段数
-mr N             指定数据文件中的最大数据行数
-W  keyword       指定gawk的兼容模式或警告等级

(2)使用的数据字段变量

默认情况下,gawk会将如下变量分配给它在文本行中发现的数据字段:

$0 代表整个文本行
$1 代表文本行中的第一个数据字段
$2 代表文本行中的第二个数据字段
$n 代表文本行中的第n个数据字段

在文本行中,每个数据字段是通过字段分隔符划分的,gawk默认的字段分隔符是任意的空白字符,例如空格或制表符。

(3)在程序脚本中使用多个命令

gawk程序允许将多条命令组合成一个正常的程序,命令之间是用分号即可。

echo "my name is bob"|gawk '{$4="jack" ; print $0}'

[root@test ~]# echo "my name is bob"|gawk '{$4="jack" ; print $0}'
my name is jack

gawk程序中的第一条命令会给字段变量$4赋值,第二条命令打印整个数据字段。

(4)从文件中读取程序

gawk编辑器允许将程序存储到文件中,然后再在命令行中引用。

cat script.gawk
{print $1 "'s home directory is " $6}

gawk -F ':' -f script.gawk /etc/passwd

[root@test ~]# gawk -F ':' -f script.gawk /etc/passwd
root's home directory is /root
bin's home directory is /bin
daemon's home directory is /sbin

可以在程序文件中指定多条命令,只要每条命令放一行即可,不需要用分号。

cat script.gawk
{
text="'s home directory is "
print $1 text $6
}

gawk -F ':' -f script.gawk /etc/passwd


[root@test ~]# gawk -F ':' -f script.gawk /etc/passwd
root's home directory is /root
bin's home directory is /bin
daemon's home directory is /sbin

可以看到gawk程序在引用变量值时并未像shell脚本一样使用美元符。

(5)在处理数据前运行脚本

gawk在读取数据前会执行BEGIN关键字后指定的程序脚本。

gawk 'BEGIN {print "hello word!"}'

[root@test ~]# gawk 'BEGIN {print "hello word!"}'
hello word!

可以看到print命令会在读取数据前显示文本,但是在它显示了文本后,会快速退出,不等待任何数据。如果想使用正常的程序脚本处理数据,必须使用另一个脚本区域来定义程序。

cat data.txt
line 1
line 2
line 3

gawk 'BEGIN {print "the data file content:"} {print $0}' data.txt


[root@test ~]# gawk 'BEGIN {print "the data file content:"} {print $0}' data.txt
the data file content:
line 1
line 2
line 3

(6)在处理数据后运行脚本

与BEGIN类似,END关键字允许指定一个程序脚本,gawk会在读完数据后执行它。

gawk 'BEGIN {print "the data file content:"} {print $0} END {print "end of file"} ' data.txt

[root@test ~]# gawk 'BEGIN {print "the data file content:"} {print $0} END {print "end of file"} ' data.txt
the data file content:
line 1
line 2
line 3
end of file

(7)综合小案例

cat script.gawk
BEGIN {
print "the latest list of users and shells"
print " UserID \t Shell"
print "------ \t -------"
FS=":"
}

{
print $1 " \t " $7
}

END {
print "this concludes ths listing"
}

gawk -f script.gawk /etc/passwd

[root@test ~]# gawk -f script.gawk /etc/passwd
the latest list of users and shells
 UserID 	 Shell
------	  -------
root 	 /bin/bash
bin 	 /sbin/nologin
daemon 	 /sbin/nologin
this concludes ths listing

二、gawk程序的进阶使用

(1)使用变量,gawk支持内建变量和自定义变量的使用。

内建变量:

gawk数据字段和记录变量
变量 描述
FIELDWIDTHS 由空格分隔的一列数字,定义了每个数据字段确切宽度
FS 输入字段分隔符
RS 输入记录分隔符
OFS 输出字段分隔符
ORS 输出记录分隔符

变量FS和OFS定义了gawk如何处理数据流中的数据字段。变量OFS具备同样的功能,只不过是用在print命令的输出上。

默认情况下,OFS设成一个空格,所以在使用命令:print $1,$2,$3会看到如下的输出结果

cat data.txt
data11,data12,data13
data21,data22,data23
data31,data32,data33


[root@test ~]# gawk 'BEGIN {FS=","} {print $1,$2,$3}' data.txt
data11 data12 data13
data21 data22 data23
data31 data32 data33

print命令会自动将OFS变量的值放置在输出中的每个字段之间,通过设置OFS变量,可以在输出中使用任意字符串来分隔字段。

[root@~]# cat data.txt
data11,data12,data13
data21,data22,data23
data31,data32,data33

[root@~]# gawk 'BEGIN {FS=",";OFS="-"} {print $1,$2,$3}' data.txt
data11-data12-data13
data21-data22-data23
data31-data32-data33

[root@~]# gawk 'BEGIN {FS=",";OFS="<->"} {print $1,$2,$3}' data.txt
data11<->data12<->data13
data21<->data22<->data23
data31<->data32<->data33

FIELDWIDTHS变量允许你不依靠字段分隔符来读取记录,在一些应用程序中,数据并没有使用字段分隔符,而是被放置在了记录中的特定列,这种情况下,必须设置FIELDWIDTHS变量来匹配数据在记录中的位置。一旦设置了FIELDWIDTHS变量,gawk就会忽略FS变量,并根据提供的字段宽度来计算字段。

cat data1.txt
1005.3243545.34
117-2.456456.03
06458.3473749.1

[root@~]# gawk 'BEGIN {FIELDWIDTHS="3 5 2 5"} {print $1,$2,$3,$4}' data1.txt
100 5.324 35 45.34
117 -2.45 64 56.03
064 58.34 73 749.1

可以看到上面的例子中使用变量FIELDWIDTHS变量定义了4个字段,gawk依此来解析数据记录,每个记录中的数字串会根据以定义好的字段长度来分割。

变量RS和ORS定义了gawk程序如何处理数据流中的记录,默认情况下,gawk程序将RS和ORS设置为换行符。默认的RS值表明,输入数据流中的每行新文本就是一条新纪录。

cat data2.txt
riley mullen
123 main street
chicago,IL 38383
(312)555-1234


frank will
456 oak street
indianapolis,in 345
(317)555-9876

gawk 'BEGIN {FS="\n";RS=""} {print $1,$4}' data2.txt

[root@test~]# gawk 'BEGIN {FS="\n";RS=""} {print $1,$4}' data2.txt
riley mullen (312)555-1234
frank will (317)555-9876

从上例中可以看到gawk程序把文件中的每行当作一个字段,把空白行当作记录分隔符。

除了字段和记录分隔符变量外,gawk还提供了其他的内建变量如下所示:(列举了几个常用的)

NF            数据文件中的字段总数
NR            已处理的输入记录数
FNR           当前数据文件中的数据行数

当要在gawk程序中跟踪数据字段和记录时,变量FNR、NR和NF用着就会很方便。NF变量可以让你在不知道具体位置的情况下就可以指定记录中的最后一个数据字段。

gawk 'BEGIN{FS=":";OFS=":"} {print $1,$NF}' /etc/passwd

[root@test~]# gawk 'BEGIN{FS=":";OFS=":"} {print $1,$NF}' /etc/passwd
root:/bin/bash
bin:/sbin/nologin
[root@test]# cat data.txt
data11,data12,data13
data21,data22,data23
data31,data32,data33

gawk 'BEGIN {FS=","} {print $1,"FNR="FNR,"NR="NR} END {print "there where",NR,"records processed"}' data.txt

[root@test]# gawk 'BEGIN {FS=","} {print $1,"FNR="FNR,"NR="NR} END {print "there where",NR,"records processed"}' data.txt
data11 FNR=1 NR=1
data21 FNR=2 NR=2
data31 FNR=3 NR=3
there where 3 records processed


gawk 'BEGIN {FS=","} {print $1,"FNR="FNR,"NR="NR} END {print "there where",NR,"records processed"}' data.txt data.txt

[root@test]# gawk 'BEGIN {FS=","} {print $1,"FNR="FNR,"NR="NR} END {print "there where",NR,"records processed"}' data.txt data.txt
data11 FNR=1 NR=1
data21 FNR=2 NR=2
data31 FNR=3 NR=3
data11 FNR=1 NR=4
data21 FNR=2 NR=5
data31 FNR=3 NR=6
there where 6 records processed

从结果可以看到,FNR变量的值在gawk处理第二个文件时被重置了,但是NR变量则在处理第二个文件时继续计数。
结果就是,如果只使用第一个文件作为输入,FNR和NR的值相同,如果使用多个文件作为输入,FNR的值只会在处理
每个文件时被重置,NR的值则会继续计数直到处理完所有的数据文件。

自定义变量:

gawk自定义变量名可以是任意数目的字母,下划线和数字,但不能以数字开头。重要的是,要记住gawk变量名区分大小写。

  • 在脚本中给变量赋值

gawk变量可以保存数值或文本值。

gawk 'BEGIN{test="this is a test";print test}'


[root@test]# gawk 'BEGIN{text="this is a test";print text}'
this is a test


[root@test]# gawk 'BEGIN{text="this is a test";print text;text=100;print text}'
this is a test
100

赋值语句还可以包含数学算式来处理数字值。

gawk 'BEGIN{x=4;x=x+4;print x}'

[root@test]# gawk 'BEGIN{x=4;x=x+4;print x}'
8
  • 在命令行上给变量赋值
[root@test]# cat data.txt
data11,data12,data13
data21,data22,data23
data31,data32,data33


cat script1
BEGIN {FS=","}
{print $n}

gawk -f script1 n=2 data.txt

[root@test]# gawk -f script1 n=2 data.txt
data12
data22
data32

但是使用命令行参数定义变量值会有一个问题,就是设置了变量后,这个值在代码的BEGIN部分不可用。

[root@test]# cat data.txt
data11,data12,data13
data21,data22,data23
data31,data32,data33

cat script
BEGIN {print "the starting value is",n;FS=","}
{print $n}

gawk -f script n=2 data.txt

[root@test]# gawk -f script n=2 data.txt
the starting value is
data12
data22
data32

可以使用-v参数来解决这个问题,-v参数允许在BEGIN代码之前设定变量。在命令行上,-v命令参数必须放在脚本代码之前。

[root@test]# cat data.txt
data11,data12,data13
data21,data22,data23
data31,data32,data33

cat script
BEGIN {print "the starting value is",n;FS=","}
{print $n}

gawk -v n=2 -f script data.txt

[root@test]# gawk -v n=2 -f script data.txt
the starting value is 2
data12
data22
data32

(2)使用模式

  • 正则表达式

在使用正则表达式时,正则表达式必须出现在它要控制的程序脚本的左花括号前。

gawk 'BEGIN {FS=","} /11/{print $1}' data.txt
[root@test]# gawk 'BEGIN {FS=","} /11/{print $1}' data.txt
data11

正则表达式/11/匹配了数据字段中含有字符串11的记录,gawk程序会用正则表达式对记录中所有的数据字段进行匹配,包括字段分隔符。

  • 匹配操作符

匹配操作符允许将正则表达式限定在记录中的特定数据字段,匹配操作符是波浪线~。可以指定匹配操作符、数据字段变量以及要匹配的正则表达式。

[root@test]# gawk 'BEGIN {FS=","} $2 ~ /^data2/{print $0}' data.txt
data21,data22,data23

匹配操作符会用正则表达式/^data2/来比较第二个数据字段,该正则表达式指明字符串要以文本data2开头。

gawk -F ':' '$1 ~ /root/{print $1,$NF}' /etc/passwd

[root@test]# gawk -F ':' '$1 ~ /root/{print $1,$NF}' /etc/passwd
root /bin/bash

这个例子会在第一个字段中查找文本root,如果在记录中找到了这个模式,他会打印该记录的第一个数据字段和最后一个数据字段值。

也可以使用!排除正则表达式的匹配。

gawk -F ':' '$1 !~ /root/{print $1,$NF}' /etc/passwd

[root@test]# gawk -F ':' '$1 !~ /root/{print $1,$NF}' /etc/passwd
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
shutdown /sbin/shutdown
halt /sbin/halt
  • 数学表达式

可以在匹配模式中使用数学表达式,可以使用任何常见的数学表达式。

x==y 
x<=y
x<y
x>=y
x>y

显示所有属于root用户组(组ID=0)的系统用户:

gawk -F ':' '$4 == 0 {print $1}' /etc/passwd

[root@test]# gawk -F ':' '$4 == 0 {print $1}' /etc/passwd
root
sync
shutdown
halt
operator
sys_admin

也可以对文本数据使用表达式,但必须小心,跟正则表达式不同,表达式必须完全匹配,数据必须跟模式严格匹配。

[root@test]# cat data.txt
data11,data12,data13
data21,data22,data23
data31,data32,data33


gawk -F ',' '$1 == "data" {print $0}' data.txt

[root@test]# gawk -F ',' '$1 == "data" {print $0}' data.txt

[root@test]# gawk -F ',' '$1 == "data11" {print $0}' data.txt
data11,data12,data13

由实例结果可以看到,第一个测试没有匹配任何记录,因为第一个数据字段值不在任何记录中,第二个测试用值data11匹配了一条记录。

(3)格式化打印

print 语句在gawk如何显示数据上并未提供多少控制。你能做的只是控制输出字段分隔符( OFS )。格式化打印命令,叫作 printf 。如果你熟悉C语言编程的话,gawk中的printf 命令用法也是一样,允许指定具体如何显示数据的指令。

printf 命令的格式:

printf "format string", var1, var2 . . .

format string 是格式化输出的关键。它会用文本元素和格式化指定符来具体指定如何呈现格式化输出。格式化指定符是一种特殊的代码,会指明显示什么类型的变量以及如何显示。gawk程序会将每个格式化指定符作为占位符,供命令中的变量使用。第一个格式化指定符对应列出的第一个变量,第二个对应第二个变量,依此类推。格式化指定符采用如下格式:
 

%[modifier]control-letter

其中 control-letter 是一个单字符代码,用于指明显示什么类型的数据,而 modifier 则定义了可选的格式化特性。

控制字母    描 述
c          将一个数作为ASCII字符显示
d          显示一个整数值
i          显示一个整数值(跟d一样)
e          用科学计数法显示一个数
f          显示一个浮点值
g          用科学计数法或浮点数显示(选择较短的格式)
o          显示一个八进制值
s          显示一个文本字符串
x          显示一个十六进制值
X          显示一个十六进制值,但用大写字母A~F

因此,如果你需要显示一个字符串变量,可以用格式化指定符 %s 。如果你需要显示一个整数值,可以用 %d 或 %i ( %d 是十进制数的C风格显示方式)。如果你要用科学计数法显示很大的值,就用 %e 格式化指定符。

gawk 'BEGIN{x = 10 * 100 ;printf "The answer is: %d\n", x}'

[root@test]# gawk 'BEGIN{x = 10 * 100 ;printf "The answer is: %d\n", x}'
The answer is: 1000

除了控制字母外,还有3种修饰符可以用来进一步控制输出。

width :指定了输出字段最小宽度的数字值。如果输出短于这个值, printf会将文本右对齐,并用空格进行填充。如果输出比指定的宽度还要长,则按照实际的长度输出。
prec :这是一个数字值,指定了浮点数中小数点后面位数,或者文本字符串中显示的最大字符数。
-(减号):指明在向格式化空间中放入数据时采用左对齐而不是右对齐。
[root@test]# cat data2.txt
riley mullen
123 main street
chicago,IL 38383
(312)555-1234


frank will
456 oak street
indianapolis,in 345
(317)555-9876


gawk 'BEGIN{FS="\n"; RS=""} {print $1,$4}' data2.txt
[root@test]# gawk 'BEGIN{FS="\n"; RS=""} {print $1,$4}' data2.txt
riley mullen (312)555-1234
frank will (317)555-9876

可以用 printf 命令来帮助格式化输出,使得输出信息看起来更美观。首先,让我们将 print命令转换成 printf 命令,看看会怎样。

gawk 'BEGIN{FS="\n"; RS=""} {printf "%s %s\n", $1, $4}' data2.txt

[root@test]# gawk 'BEGIN{FS="\n"; RS=""} {printf "%s %s\n", $1, $4}' data2.txt
riley mullen (312)555-1234
frank will (317)555-9876


它会产生跟 print 命令相同的输出。 printf 命令用 %s 格式化指定符来作为这两个字符串值的占位符。注意,你需要在 printf 命令的末尾手动添加换行符来生成新行。没添加的话, printf 命令会继续在同一行打印后续输出。 

printf 命令在处理浮点值时也非常方便。通过为变量指定一个格式,你可以让输出看起来更统一。下面的例子中使用 %5.1f 格式指定符来强制 printf 命令将浮点值近似到小数点后一位。

cat test.txt
130 120 135
110 879 675
234 567 356

gawk '{
total = 0
for (i = 1; i < 4; i++)
{
total += $i
}
avg = total / 3
printf "Average: %5.1f\n",avg
}' test.txt

[root@test]# gawk '{
> total = 0
> for (i = 1; i < 4; i++)
> {
> total += $i
> }
> avg = total / 3
> printf "Average: %5.1f\n",avg
> }' test.txt
Average: 128.3
Average: 554.7
Average: 385.7

通过添加一个值为 16 的修饰符,我们强制第一个字符串的输出宽度为16个字符。默认情况下,printf 命令使用右对齐来将数据放到格式化空间中。要改成左对齐,只需给修饰符加一个减号即可。

[root@test]# cat data2.txt
riley mullen
123 main street
chicago,IL 38383
(312)555-1234


frank will
456 oak street
indianapolis,in 345
(317)555-9876


gawk 'BEGIN{FS="\n"; RS=""} {printf "%16s %s\n", $1,$4}' data2.txt

[root@test]# gawk 'BEGIN{FS="\n"; RS=""} {printf "%16s %s\n", $1,$4}' data2.txt
    riley mullen (312)555-1234
      frank will (317)555-9876


gawk 'BEGIN{FS="\n"; RS=""} {printf "%-16s %s\n", $1,$4}' data2.txt
[root@test]# gawk 'BEGIN{FS="\n"; RS=""} {printf "%-16s %s\n", $1,$4}' data2.txt
riley mullen     (312)555-1234
frank will       (317)555-9876

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章