awk进阶

24 篇文章 0 订阅
6 篇文章 0 订阅

一 使用变量

1.内建变量

awk编程语言支持两种不同类型的
变量:
 内建变量
 自定义变量
awk有一些内建变量。这些变量存放用来处理数据文件中的数据字段和记录的信息。也可以在gawk程序里创建你自己的变量。

1.1. 字段和记录分隔符变量

awk数据字段和记录变量 


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

字段:就是数据内容有多少列

记录:每一行的数据内容

记录分隔符:每一行的分隔符


 

例如

$ cat data1
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35

$ awk 'BEGIN{FS=","} {print $1,$2,$3}' data1
data11 data12 data13
data21 data22 data23
data31 data32 data33

通过设置OFS变量,可以在输出中使用任意字符串来分隔字段。

$ awk 'BEGIN{FS=","; OFS="-"} {print $1,$2,$3}' data1
data11-data12-data13
data21-data22-data23
data31-data32-data33

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

$ cat data2
Riley Mullen
123 Main Street
Chicago, IL 60601
(312)555-1234
Frank Williams
456 Oak Street
Indianapolis, IN 46201
(317)555-9876
Haley Snell
4231 Elm Street
Detroit, MI 48201
(313)555-4938
$ gawk 'BEGIN{FS="\n"; RS=""} {print $1,$4}' data2
Riley Mullen (312)555-1234
Frank Williams (317)555-9876
Haley Snell (313)555-4938

太好了,现在gawk把文件中的每行都当成一个字段,把空白行当作记录分隔符。

RS和ORS RS默认是\n分隔每行,如果想指定以某个字符作为分隔符来处理记录:
# echo "www.baidu.com/user/test.html" |awk 'BEGIN{RS="/"}{print $0}' 
www.baidu.com
user
test.html

 

1.2. 数据变量

awk内建变量


变 量                 描 述

ARGC              当前命令行参数个数
ARGIND          当前文件在ARGV中的位置
ARGV              包含命令行参数的数组(常用参数)
CONVFMT       数字的转换格式(参见printf语句),默认值为%.6 g
ENVIRON        当前shell环境变量及其值组成的关联数组
ERRNO            当读取或关闭输入文件发生错误时的系统错误号
FILENAME       用作gawk输入数据的数据文件的文件名(常用参数)
FNR                  当前数据文件中的数据行数(常用参数)
IGNORECASE 设成非零值时,忽略gawk命令中出现的字符串的字符大小写
NF                     数据文件中的字段总数(常用参数)--数据文件中的总共有多少列
NR                     已处理的输入记录数(常用参数)--已处理的输入数据内容的行数
OFMT                数字的输出格式,默认值为%.6 g
RLENGTH         由match函数所匹配的子字符串的长度
RSTART            由match函数所匹配的子字符串的起始位置


ARGC支持命令行中传入a w k脚本的参数个数。ARGV是ARGC的参数排列数组,其中每一元素表示为ARGV [n],n为期望访问的命令行参数。
ENVIRON 支持系统设置的环境变量,要访问单独变量,使用实际变量名,例如ENVIRON [“EDITOR”] =“Vi”。
FILENAME支持awk脚本实际操作的输入文件。因为a w k可以同时处理许多文件,因此如果访问了这个变量,将告之系统目前正在浏览的实际文件。
FNR支持awk目前操作的记录数。其变量值小于等于NR。如果脚本正在访问许多文件,每一新输入文件都将重新设置此变量。

FS用来在awk中设置域分隔符,与命令行中- F选项功能相同。缺省情况下为空格。如果用逗号来作域分隔符,设置FS = ","。
NF支持记录域个数,在记录被读之后再设置。
OFS允许指定输出域分隔符,缺省为空格。如果想设置为#,写入OFS = " # "。
ORS为输出记录分隔符,缺省为新行(\n)。
RS是记录分隔符,缺省为新行(\n)。

例如

(1)ARGC和ARGV

awk 'BEGIN{print ARGC,ARGV[1]}' data

ARGC变量表明命令行上有两个参数。ARGV数组从索引0开始,代表的是命令。第一个数组值是gawk命令后的第一个命令行
参数。

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

ARGC是命令行参数数量 ARGV是将命令行参数存到数组,元素由ARGC指定,数组下标从0开始

# awk 'BEGIN{print ARGC}' 1 2 3 4

# awk 'BEGIN{print ARGV[0]}'

awk

# awk 'BEGIN{print ARGV[1]}' 1 2

1

# awk 'BEGIN{print ARGV[2]}' 1 2

2

(2)NF变量含有数据文件中最后一个数据字段的数字值,可以在它前面加个美元符将其用作字段变量

NF是字段个数。即有多少列

# echo "a b c d e f" |awk '{print NF}'

6

打印最后一个字段:

# echo "a b c d e f" |awk '{print $NF}'

f

打印倒数第二个字段:

# echo "a b c d e f" |awk '{print $(NF-1)}'

e

(3)FNR和NR变量虽然类似,但又略有不同。FNR变量含有当前数据文件中已处理过的记录数(行数),NR变量则含有已处理过的记录总数(总行数)。

这个脚本会打印第一个数据字段的值和FNR变量的当前值。注意,当gawk程序处理第二个数据文件时,FNR值被设回了1

$awk 'BEGIN{FS=","}{print $1,"FNR="FNR}' data1 data1
data11 FNR=1
data21 FNR=2
data31 FNR=3
data11 FNR=1
data21 FNR=2
data31 FNR=3

 

FNR的值会在处理每个数据文件时被重置,而NR的值则会继续计数直到处理完所有的数据文件。

$awk 'BEGIN{FS=","}{print $1,"FNR="FNR,"NR="NR}END{print "records number=",NR}' data1 data1

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
records number= 6

 

2.自定义变量

2.1. 在脚本中给变量赋值

$awk 'BEGIN{ n="this is a test";print n}'
this is a test

$awk 'BEGIN{x=4; x= x * 2 + 3; print x}'
11
awk编程语言包含了用来处理数字值的标准算数操作符。其中包括求余符号(%)和幂运算符号(^或**)。

2.2在命令行上给变量赋值

$ cat script1
BEGIN{FS=","}
{print $n}
$ awk -f script1 n=2 data1
data12
data22
data32

 

允许你在BEGIN代码之前设定变量,在命令行上,-v命令行参数必须放在脚本代码之前。

$ cat script2
BEGIN{print "The starting value is",n; FS=","}
{print $n}

$ awk -v n=3 -f script2 data1
The starting value is 3
data13
data23
data33
$

2.3 变量赋值

# awk -v a=123 'BEGIN{print a}' 
123 
系统变量作为awk变量的值: 
# a=123 
# awk -v a=$a 'BEGIN{print a}' 
123 
或使用单引号 
# awk 'BEGIN{print '$a'}' 
123

二 处理数组

2.1.定义数组变量

数组变量赋值的格式如下:var[index] = element

数组是无序存储

在引用数组变量时,必须包含索引值来提取相应的数据元素值。

$ awk 'BEGIN{ capital["Illinois"] = "Springfield" ;print capital["Illinois"]}'
Springfield
$

在引用数组变量时,会得到数据元素的值

$awk 'BEGIN{a[1]=1;a[2]=2;total=a[1]+a[2];print total}'
3

2.2.遍历数组变量

用for语句的一种特殊形式。
for (var in array)
{
statements
}

例如

$awk 'BEGIN{var["a"]=1;var["b"]=2;var["c"]=3;for(test in var){print "index="test,"-var:"var[test]}}'
index=a -var:1
index=b -var:2
index=c -var:3
3.删除数组变量

从关联数组中删除数组索引要用一个特殊的命令:delete array[index]

删除命令会从数组中删除关联索引值和相关的数据元素值。

$awk 'BEGIN{var["a"]=1;var["b"]=2;var["c"]=3;delete var["b"];print "--------";for(test in var){print "index="test,"-var:"var[test]}}'
--------
index=a -var:1
index=c -var:3

三 使用模式

3.1 正则表达式

用基础正则表达式(BRE)或扩展正则表达式(ERE)来选择程序脚本作用在数据流中的哪些行上

$awk 'BEGIN{FS=","}/11/{print $1}' data1
data11

$ gawk 'BEGIN{FS=","} /,d/{print $1}' data1
data11
data21
data31

3.2匹配操作符

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

例如:$1 ~ /^data1/

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

$awk 'BEGIN{FS=","} $2 ~ /^data2/{print $0}' data1
data21,data22,data23,data24,data25

awk程序脚本中经常用它在数据文件中搜索特定的数据元素

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

以用!符号来排除正则表达式的匹配,比如$1 !~ /expression/
如果记录中没有找到匹配正则表达式的文本,程序脚本就会作用到记录数据。

$ awk -F: '$1 !~ /root/{print $1,$NF}' /etc/passwd
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin

3.3数学表达式

跟正则表达式不同,表达式必须完全匹配。数据必须跟模式严格匹配。

可以使用任何常见的数学比较表达式。
 x == y:值x等于y。
 x <= y:值x小于等于y。
 x < y:值x小于y。
 x >= y:值x大于等于y。
 x > y:值x大于y。

$awk -F, '$1 == "data21" {print $1}' data1
data21

四 结构化命令

4.1if 语句

if语句定义一个求值的条件,并将其用圆括号括起来。如果条件求值为TRUE,紧跟在if语句后的语句会执行。如果条
件求值为FALSE,这条语句就会被跳过。可以用这种格式:

if (condition)
statement1

也可以将它放在一行上,像这样:

if (condition) statement1

例如

$ cat data4
10
5
13
50
34
$ awk '{if ($1 > 20) print $1}' data4
50
34
$

如果需要在if语句中执行多条语句,就必须用花括号将它们括起来。

$ awk '{if ( $1 > 10) { x = $1*2;print x}}' data4
26
100
68

可以在单行上使用else子句,但必须在if语句部分之后使用分号。
if (condition) statement1; else statement2

if语句也支持else子句,允许在if语句条件不成立的情况下执行一条或多条语句。

4.2 while 语句

是while语句的格式。
while (condition)
{
statements
}

4.3 do-while 语句

do
{
statements
} while (condition)

4.4 for 语句

for语句C语言风格

for( variable assignment; condition; iteration process)

{

 statements

}

用for语句的一种特殊形式--for语句遍历数组。
for (var in array)
{
statements
}

或者

for (var in array) statement

五 格式化打印

printf命令,允许指定具体如何显示数据的指令。printf命令的格式:
printf "format string", var1, var2 . . .

format string是格式化输出的关键,格式化指定符采用如下格式:%[modifier]control-letter

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

格式化指定符的控制字母


控制字母   描述

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


 width:指定了输出字段最小宽度的数字值。如果输出短于这个值,printf会将文本右
对齐,并用空格进行填充。如果输出比指定的宽度还要长,则按照实际的长度输出。
 prec:这是一个数字值,指定了浮点数中小数点后面位数,或者文本字符串中显示的最
大字符数。
 -(减号):指明在向格式化空间中放入数据时采用左对齐而不是右对齐。

用修饰符来格式化第一个字符串值。

强制第一个字符串的输出宽度为16个字符。默认情况下,printf命令使用右对齐来将数据放到格式化空间中.。
$ awk 'BEGIN{FS="\n"; RS=""} {printf "%16s %s\n", $1, $4}' data2
Riley Mullen (312)555-1234
Frank Williams (317)555-9876
Haley Snell (313)555-4938

改成左对齐,只需给修饰符加一个减号即可。

$ awk 'BEGIN{FS="\n"; RS=""} {printf "%-16s %s\n", $1, $4}' data2
Riley Mullen (312)555-1234
Frank Williams (317)555-9876
Haley Snell (313)555-4938
$

六 内建函数

6.1 数学函数

atan2(x, y)  x/y的反正切,x和y以弧度为单位
cos(x)         x的余弦,x以弧度为单位
exp(x)         x的指数函数
int(x)           x的整数部分,取靠近零一侧的值
log(x)          x的自然对数
rand( )         比0大比1小的随机浮点值
sin(x)           x的正弦,x以弧度为单位
sqrt(x)         x的平方根
srand(x)      为计算随机数指定一个种子值

6.2 字符串函数

asort(s [,d])     将数组s按数据元素值排序。索引值会被替换成表示新的排序顺序的连续数字。另外,如果指定了d,则排序后的数组会存储在数组d中
asorti(s [,d])    将数组s按索引值排序。生成的数组会将索引值作为数据元素值,用连续数字索引来表明排序顺序。另外如果指定了d,排序后的数组会存储在数组d中
gensub(r, s, h [, t])   查找变量$0或目标字符串t(如果提供了的话)来匹配正则表达式r。如果h是一个以g或G开头的字符串,就用s替换掉匹配的文本。如果h是一个数字,它表示要替换掉第h处r匹配的地方
gsub(r, s [,t])           查找变量$0或目标字符串t(如果提供了的话)来匹配正则表达式r。如果找到了,就全部替换成字符串s
index(s, t)               返回字符串t在字符串s中的索引值,如果没找到的话返回0
length([s])               返回字符串s的长度;如果没有指定的话,返回$0的长度
match(s, r [,a])        返回字符串s中正则表达式r出现位置的索引。如果指定了数组a,它会存储s中匹配正则表达式的那部分

split(s, a [,r])           将s用FS字符或正则表达式r(如果指定了的话)分开放到数组a中。返回字段的总数
sprintf(format,variables)    用提供的format和variables返回一个类似于printf输出的字符串
sub(r, s [,t])             在变量$0或目标字符串t中查找正则表达式r的匹配。如果找到了,就用字符串s替换掉第一处匹配
substr(s, i [,n])        返回s中从索引值i开始的n个字符组成的子字符串。如果未提供n,则返回s剩下的部分
tolower(s)               将s中的所有字符转换成小写
toupper(s)              将s中的所有字符转换成大写

6.3 时间函数

mktime(datespec) 将一个按YYYY MM DD HH MM SS [DST]格式指定的日期转换成时间戳值①
strftime(format[,timestamp])将当前时间的时间戳或timestamp(如果提供了的话)转化格式化日期(采用shell函数date()的格式)
systime( ) 返回当前时间的时间戳

七  自定义函数

7.1定义函数
要定义自己的函数,必须用function关键字。
function name([variables])
{
statements
}

函数还能用return语句返回值:return value

7.2使用自定义函数

$awk 'function my(){printf "%-16s -%s\n",$1,$4}BEGIN{FS="\n";RS=""}{my()}' data2
Riley Mullen - (312)555-1234
Frank Williams - (317)555-9876
Haley Snell - (313)555-4938
$

7.3 创建函数库

创建一个存储所有gawk函数的文件。
$ cat funclib
function myprint()
{
printf "%-16s - %s\n", $1, $4
}
function myrand(limit)
{
return int(limit * rand())
}
function printthird()
{
print $3
}
$

funclib文件含有三个函数定义。需要使用-f命令行参数来使用它们。很遗憾,不能将-f命令行参数和内联gawk脚本放到一起使用,不过可以在同一个命令行中使用多个-f参数。

要使用库,只要创建一个含有你的gawk程序的文件,然后在命令行上同时指定库文件
和程序文件就行了。
$ cat script4
BEGIN{ FS="\n"; RS=""}
{
myprint()
}
$ awk -f funclib -f script4 data2
Riley Mullen - (312)555-1234
Frank Williams - (317)555-9876
Haley Snell - (313)555-4938
$

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值