一 使用变量
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
$