第十九章 文本处理流编辑器:awk编程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十九章 文本处理流编辑器:awk编程相关的知识,希望对你有一定的参考价值。
第十九章 文本处理流编辑器:awk编程
名词解释
awk 是一种编程语言,用于linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件、或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大个编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如:数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。
awk命令格式和选项
语法形式
awk [option] ‘script‘ var=value file(s)
awk [option] -f scriptfile var=value file(s)
常用命令选项
- -F fs :fs指定输入分隔符,fs可以是字符串或正则表达式,如: -F:。
- -v var=value :赋值一个用户定义变量,将外部变量传递给awk。
- -f scriptfile :从脚本文件中读取awk命令。
- -m[fr] val :对val值设置内在限制,-mf选项限制分配给val的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
awk模式和操作
awk脚本是由模式和操作组成的
模式
模式可以是以下任意一个:
- /正则表达式/ :适用通配符的扩展集。
- 关系表达式:适用运算符进行操作,可以是字符串或数字的比较测试。
- 模式匹配表达式:用运算符
~
(匹配) 和~!
(不匹配)。 - BEGIN语句块、pattern语句块、END语句块:参见awk的工作原理:见本章后边章节。
操作
操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内,主要部分是:
- 变量或数组赋值
- 输出命令
- 内置函数
- 控制流语句
awk脚本基本结构
awk ‘BEGIN{ print "start" } pattern{ commands } END{ print "end"}‘ file
一个awk脚本通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块 三部分组成,这三个部分是可选的。
任意一个部分都可以不出现在脚本中,脚本通常是在 单引号或双引号中,例如:
#脚本在单引号中:
awk ‘BEGIN{ i=0 } { i++ } END{ print i }‘ filename
#脚本在双引号中:
awk "BEGIN{ i=0 } { i++ } END{ print i }" filename
awk的工作原理
awk ‘BEGIN{ commands } pattern{ commands } END{ commands }‘
- 第一步:执行
BEGIN{ commands }
语句块中的语句。 - 第二步:从文件或标准输入(stdin)读取一行,然后执行
pattern{ commands }
语句块,它逐行描述文件,从第一行到最后一行重复这个过程,知道文件全部被读取完毕。 - 第三步:当读至输入流末尾时,执行E
ND{ commands }
语句块。
BEGIN语句块在awk开始 从输入流中 读取之前被执行,这是一个可选的语句块,比如:变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
END语句块在awk从输入流中 读取完所有的行之后即被执行,比如:打印所有行的分析结果这类信息 都是在END语句块中完成,它也是一个可选语句块。
pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取的行,awk读取的每一行都会执行该语句块。
示例
echo -e "A line 1
A line 2" | awk ‘BEGIN{ print "start:" } { print } END{ print "end:" }‘
输出:
start:
A line 1
A line 2
end:
当使用不带参数print时,它就打印当前行,当print的参数是以逗号进行分割时,打印时则以空格作为定界符。在awk中的print语句块中双引号是被当作拼接符使用,例如:
echo | awk ‘{ var1="v1";var2="v2";var3="v3"; print var1,var2,var3}‘
结果:
v1 v2 v3
双引号拼接使用:
echo | awk ‘{ var1="v1";var2="v2";var3="v3"; print var1"="var2"="var3}‘
结果 :
v1=v2=v3
{}类似一个循环体,会对文件中的每一行进行迭代,通常变量初始化语句(如:i=0)以及打印文件头部的语句放入BEGIN语句块中,将打印的结果等语句放在END语句块中。
awk内置变量(预定义变量)
说明:[][][A][N][P][G]
表示第一个支持变量的工具,[A]=awk、[N]=nawk、[P]=POSIXawk、[G]=gawk
$n :当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段。
$0 :这个变量 包含执行过程中 当前行的文本内容。
[N]:ARGC 命令行参数的数目。
[G]:ARGIND 命令行中当前文件的位置(从0开始计算)。
[N]:ARGV 包含命令行参数的数组。
[G]:CONVFMT 数字转换格式(默认值为%.6g)
[P]:ENVIRON 环境变量关联数组。
[N]:ERRNO 最后一个系统错误的描述。
[G]:FIELDWIDTHS 字段宽度列表(用空格键分隔)。
[A]:FILENAME 当前输入文件的名。
[P]:FNR 同NR,但相对于当前文件。
[A]:FS字段分隔符(默认是任何空格)。
[G]:IGNORECASE 如果为真,则进行忽略大小写的匹配。
[A]:NF 打印当前行的最后一个字段。
[A]:NR 打印当前行的行号。
[A]:OFMT 数字的输出格式(默认值是%.6g)。
[A]:OFS 输出字段分隔符(默认值是一个空格)。
[A]:ORS 输出记录分隔符(默认值时一个换行符)。
[A]:RS 记录分隔符(默认是一个换行符)。
[N]:RSTART 由match函数所匹配的字符串的第一个位置。
[N]:RLENGTH 由match函数所匹配的字符串的长度。
[N]:SUBSEP 数组下标分隔符(默认值是34)。
示例:
echo -e "line1 f1 f1
line2 f2 f2
line3 f3 f3" | awk ‘{print "Line No:"NR",No of field:"NF, "$0="$0, "$1="$1, "$2="$2, "$3="$3}‘
输出:
Line No:1,No of field:3 $0=line1 f1 f1 $1=line1 $2=f1 $3=f1
Line No:2,No of field:3 $0=line2 f2 f2 $1=line2 $2=f2 $3=f2
Line No:3,No of field:3 $0=line3 f3 f3 $1=line3 $2=f3 $3=f3
解释:
NR:表示打印当前读取内容所在的行号
NF:表示打印当前行的最后一个字段
使用print $NF
可以打印出一行中的最后一个字段,使用$(NF-1)
则是倒数第二个字段,其他依次类推:
[[email protected] awk]# echo -e "line1 f2 f3
line2 f4 f5" | awk ‘{print $NF}‘
f3
f5
[[email protected] awk]# echo -e "line1 f2 f3
line2 f4 f5" | awk ‘{print $(NF-1)}‘
f2
f4
打印每一行的第二和第三个字段:
[[email protected] awk]# echo -e "line1 f2 f3
line2 f4 f5" | awk ‘{print $2,$3}‘
f2 f3
f4 f5
统计文件中的行数:
[[email protected] awk]# echo -e "line1 f2 f3
line2 f4 f5" | awk ‘END{print NR}‘
2
以上命令只使用了END语句块,在读入每一行的时候,awk会将NR更新为对应的行号,当到达最后一行NR的值就是最后一行的行号,所以END语句块中的NR就是文件的行数。
计算每一行中的第一个字段累加的例子:
[[email protected] awk]# seq 5 | awk ‘BEGIN{ sum=0; print "计算总和:" } {print $1"+"; sum+=1 } END{print "相加总和是:"sum}‘
计算总和:
1+
2+
3+
4+
5+
相加总和是:5
将外部变量传递给awk
借助-v选项,可以将外部值(并非stdin)传递给awk:
[[email protected] awk]# abc=2000
[[email protected] awk]# echo | awk -v def=$abc ‘{ print def }‘
2000
另一种传递外部变量方法:
[[email protected] awk]# echo | awk ‘{ print v1,v2 }‘ v1=$var1 v2=$var2
hello world
当输入来自于文件时,使用:
awk ‘{ print v1,v2 }‘ v1=$var1 v2=$var2 filename
#此处有问题。
以上方法中,变量之间用空格分隔作为awk的命令行参数 跟随在BEGIN、{}和END语句之后。
awk运算与判断
awk支持多种运算,还提供了内置的运算函数(如log、sqr、cos、sin等)和一些用于对字符串进行操作的函数(如length、substr等)。awk中也提供了关系判断,允许多种测试作为样式匹配,还提供了模式匹配表达式 ~(匹配)和 ~!(不匹配)。awk也支持用逻辑运算符。
算术运算符
运算符 | 描述 |
---|---|
+ - | 加,减 |
* / & | 乘,除,求余 |
+ - ! | 一元加,减和逻辑非 |
^ *** | 求幂 |
++ -- | 增加或减少,作为前缀或后缀 |
例:
[[email protected] awk]# awk ‘BEGIN{a="b"; print a++,++a;}‘
0 2
注意:所有用作算术运算符进行操作,操作数自动转为数值,所有非数值都变为0; 里边的++就等于 +1;a++就等于0+1。
再看下面的例子:
[[email protected] awk]# awk ‘BEGIN{a="b"; print a++,a,++a,++a;}‘
0 1 2 3
赋值运算符
运算符 | 描述 |
---|---|
= | 简单的赋值运算符 |
+= | 加法赋值运算符 |
-= | 减法赋值运算符 |
*= | 乘法赋值运算符 |
/= | 除法赋值运算符 |
%= | 取模赋值运算符 |
^= | 二进制位异或运算 |
**= | 乘幂赋值运算符 |
例:
a+=5;等同于: a=a+5 ;其他运算符也同样
逻辑运算符
运算符 | 描述 |
---|---|
|| | 逻辑 或 |
&& | 逻辑 与 |
例如:
[[email protected] awk]# awk ‘BEGIN{a=1;b=2;print (a>5 && b<=2),(a>5 || b<=2);}‘
0 1
&&:代表两边条件必须都满足
||:达标两边条件一个满足即可
关系运算符
运算符 | 描述 |
---|---|
< | 小于 |
<= | 小于等于 |
> | 大于 |
>= | 大于等于 |
!= | 不等于 |
== | 等于 |
例如:
[[email protected] awk]# awk ‘BEGIN{a=11; if(a>=9){print "ok";}}‘
ok
注意:> < 可以作为字符串比较,也可以作为数值比较,关键看操作符。如果是字符串会转换为字符串比较。两个都为数字才转为数值比较。字符串比较:是按照ASCII码的对应的顺序比较。
其它运算符
运算符 | 描述 |
---|---|
$ | 字段引用 |
空格 | 字符串连接符 |
?: | C条件表达式 |
in | 数组中是否存在某键值 |
not in | 数组中不存在某键值 |
例如:
[[email protected] awk]# awk ‘BEGIN{ print 5==5?"ok":"err";}‘
ok
[[email protected] awk]# awk ‘BEGIN{ print 5==6?"ok":"err";}‘
err
[[email protected] awk]# awk ‘BEGIN{a="b"; arr[0]="b"; arr[b]="c"; print (a in arr);}‘
0
[[email protected] awk]# awk ‘BEGIN{a="b"; arr[0]="b"; arr[b]="c"; print (b in arr);}‘
1
运算级别优先级表
级别越高越优先
级别 | 运算符 | 说明 |
---|---|---|
1 | =,+=,-=,*=,/=,%=,&=,^=,|=,<<=,>>= | 赋值、运算、赋值 |
2 | || | 逻辑或 |
3 | && | 逻辑与 |
4 | | | 按位或 |
5 | ^ | 按位异或 |
6 | & | 按位与 |
7 | ==,!= | 等于,不等于 |
8 | <=,>=,<,> | 小于等于,大于等于,小于,大于 |
9 | <<,>> | 按位左移,按位右移 |
10 | +,- | 加,减 |
11 | *,/,% | 乘,除,取模 |
12 | !,~ | 逻辑非,按位取反或补码 |
13 | -,+ | 正,负 |
awk高级输入输出
读取下一条记录
awk中next
语句使用:在循环逐行匹配,如果遇到next,就会跳过当前行,直接忽略下面语句。而进行下一行匹配。next语句一般用于多行合并:
[[email protected] awk]# cat ceshi
a
b
c
d
e
[[email protected] awk]# awk ‘NR%2==1{next}{print NR,$0;}‘ ceshi
2 b
4 d
? 上例说明:当记录行号除以2余1,就推过当前行。下面的print NR,$0
也不会执行。下一行开始,程序又开始判断NR%2
值,这个时候记录行号为2,就会执行下面语句块:print NR,$0
分析发现需要将包含有“web”行进行跳过,然后需要将内容与下面行合并为一行:
[[email protected] awk]# cat test2
web01[192.168.2.100]
httpd ok
tomcat ok
sendmail ok
web02[192.168.2.101]
httpd ok
postfix ok
web03[192.168.2.102]
mysqld ok
httpd ok
[[email protected] awk]# awk ‘/^web/{T=$0;next;}{print T": "$0;}‘ test2
web01[192.168.2.100]: httpd ok
web01[192.168.2.100]: tomcat ok
web01[192.168.2.100]: sendmail ok
web02[192.168.2.101]: httpd ok
web02[192.168.2.101]: postfix ok
web03[192.168.2.102]: mysqld ok
web03[192.168.2.102]: httpd ok
简单的读取一条记录
awk getline
用法:输出重定向需用到getline函数
。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF NR和FNR等内建变量赋值。如果得到一条记录,geline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,返回-1。
getline语法:getline var,变量var包含了特淡定行的内容。
awk getline整体用法说明:
- 当其左右无重定向符
|
或<
时:getline作用于当前文件,读入当前文件的第一行给其后跟的变量var
或$0
(无变量),应该注意到,由于awk在处理getline之前已经读入了一行,所以getline得到的返回结果是隔行的。 - 当其左右有重定向符
|
或<
时:getline作用于重定向输入文件,由于该文件时刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。
示例:
执行linux的date命令,并通过管道输出给getline,然后再把输出赋值给自定义变量out,并打印它:
[[email protected] awk]# awk ‘BEGIN{ "date" | getline out;print out }‘
Tue Apr 17 14:47:31 CST 2018
执行shell的date命令,并通过管道输出给getline,然后getline从管道中读取并将输入赋值给out,split函数把变量out转化成数组mon,然后打印数组mon的第二个元素:
[[email protected] awk]# date
Tue Apr 17 15:29:01 CST 2018
[[email protected] awk]# awk ‘BEGIN{ "date" | getline out; split(out,mon); print mon[2] }‘
Apr
命令ls的输出传递给geline作为输入,循环使getline从ls的输出中读取一行,并把它打印到屏幕。这里没有输入文件,因为BEGIN块在打开输入文件前执行,所有可以忽略输入文件。
[[email protected] awk]# ls
ceshi test test2
[[email protected] awk]# awk ‘BEGIN{ while( "ls" | getline) print }‘
ceshi
test
test2
关闭文件
awk中允许在程序中关闭一个输入或输出文件,方法是使用awk的close语句。
close("filename")
? filename可以是getline打开的文件,也可以是stdin,包含文件名的变量或者getline使用的确切命令。或一个输出文件,可以是stdout,包含文件名的变量或使用管道的确切命令。
输出到一个文件
awk中允许用如下方式将结果输出到一个文件:
[[email protected] awk]# echo | awk ‘{printf ("hello world!
") > "datafile"}‘
[[email protected] awk]# cat datafile
hello world!
或
[[email protected] awk]# echo | awk ‘{printf ("hello world!
") >> "datafile2"}‘
[[email protected] awk]# cat datafile2
hello world!
设置字段定界符
默认的字段定界符是空格,可以使用-F “定界符”
明确指定一个定界符:
awk -F: ‘{printf $NF}‘ /etc/passwd
或
awk ‘BEGIN{ FS=":"} {print $NF}‘ /etc/passwd
? 在BEGIN语句块中则可以用OFS="定界符"
设置输出字段的定界符。
流程控制语句
在linux awk的while、do-while、for语句中允许使用break、continue语句来控制流程走向,也允许使用exit这样的语句来退出。break中断当前正在执行的循环并调到循环外执行吓一跳命令。if是流程选择用法。awk中 流程控制语句,语法结构,与C语言类似。有了这些语句。其实很多shell程序都是可以交给awk,而且性能是非常快的。下面是各个语句用法。
条件判断语句
if(表达式)
语句1
else
语句2
? 表达式中语句1 可以是多个语句,为了方便判断和阅读,最好将多个语句用{}括起来。awk分支结构允许嵌套,其格式为:
if(表达式)
{语句1}
else if(表达式)
{语句2}
else
{语句3}
示例:
#!/bin/bash
awk ‘BEGIN{
test=40;
if(test>90)
{print "very good!";}
else if(test>60)
{print "good!";}
else
{print "no pass";}
}
‘
运行输出:
no pass
? 每条命令语句后面可以用;
分号结尾。
循环语句
while语句
while(表达式)
{语句}
示例:
awk ‘BEGIN{
test=5;
total=0;
while(i<test)
{
total+=i;
i++;
}
print "结果:"total;
}‘
运行结果
结果:10
i默认是0;此例为:计算0+1+2+3+4等于多少
for循环
格式1
for(变量 in 数组)
{语句}
示例:
awk ‘BEGIN{
for(k in ENVIRON){
print k"="ENVIRON[k];
}
}‘
TERM=linux
G_BROKEN_FILENAMES=1
SHLVL=1
pwd=/root/text
...
logname=root
HOME=/root
SSH_CLIENT=192.168.1.21 53087 22
? 注:ENVIRON是awk常量,是字典型数组。
格式2
for(变量;条件;表达式)
{语句}
示例:
awk ‘BEGIN{
total=0
for(i=0;i<5;i++)
{total+=i;}
print total
}‘
运行结果:
10
do循环
do
{语句} while(条件)
示例:
awk ‘BEGIN{
total=0;
i=0;
do {total+=i;i++;} while(i<5)
print total;
}‘
运行结果:
10
其他语句
- break:当break语句用于while或for语句时,导致退出程序循环。
- continue:当continue语句用于while或for语句时,使程序循环移动到下一个迭代。
- next:能够导致读入下一个输入行,并返回到脚本的顶部 。这可以避免对当前输入行执行其他的操作过程。
- exit:语句使主输入循环退出 并将控制转义到END,如果END存在的话,就执行END规则;如果没有定义END规则,就在END中应用exit语句,终止脚本的执行。
数组应用
数组是awk的灵魂,处理文本中最不能少的就是它的数组处理。因为数组索引(下标)可以是数字和字符串,在awk数组中叫做关联数组(associative arrays)。awk中的数组不必提前声明,也不必声明大小。数组元素用0或空字符串来初始化,这根据上下文而定。
数组的定义
数字做数组索引(也叫下标):
Array[1]="sun"
Array[2]="kai"
字符串做数组索引(下标):
Array["first"]="www"
Array["last"]="name"
Array["birth"]="1999"
使用print Array[1]会打印出sun;使用print Array["last"]会得到name。
读取数组的值
{ for(item in array){print array[item]};} #输出的顺序是随机的
{ for(i=1;i<=len;i++){print array[i]};} #len是数组的长度
数组相关函数
得到数组长度:
[[email protected] awk]# awk ‘BEGIN{info="it is a test";lens=split(info,tA," ");print length(tA),lens;}‘
4 4
? length返回字符串以及数组长度,split进行分割字符串为数组,也会返回分割得到数组长度。
[[email protected] awk]# awk ‘BEGIN{info="it is a test"; split(info,tA," "); print asort(tA);}‘4
? asort对数组进行排序,返回数组长度。
输出数组内容(无序,有序输出):
无序输出:
[[email protected] awk]# awk ‘BEGIN{info="it is a test"; split(info,tA," "); for(k in tA){print k,tA[k];}}‘
4 test
1 it
2 is
3 a
? for ... in
输出,因为数组是关联数组,默认是无序的。所以通过for ... in
得到是无序的数组。如果需要得到有序数组,需要通过下标获得。
有序输出:
方法1:
[[email protected] awk]# awk ‘BEGIN{info="it is a test"; split(info,tA," "); for(k=1;k<=length(tA);k++){print k,tA[k];}}‘
1 it
2 is
3 a
4 test
方法2:
[[email protected] awk]# awk ‘BEGIN{info="it is a test"; split(info,tA," "); for(k=1;k<=asort(tA);k++){print k,tA[k];}}‘
1 a
2 is
3 it
4 test
方法3:
[[email protected] awk]# awk ‘BEGIN{info="it is a test"; Len=split(info,tA," "); for(k=1;k<=Len;k++){print k,tA[k];}}‘
1 it
2 is
3 a
4 test
? 注意:数组小标是从1开始,与C、python数组不一样 小标从0开始。
判断键值存在以及删除键值:
#错误的判断方法:
awk ‘BEGIN{tB["a"]="a1";tB["b"]="b1";if(tB["c"]!="1"){print "no found";};for(k in tB){print k,tB[k];}}‘
no found
a a1
b b1
c
? 以上出现奇怪问题,tB[“c”]
没有定义,但是循环时候,发现已经存在该键值,它的值为空,这里需要注意,awk数组是关联数组,只要通过数组引用它的key,就会自动创建改序列。
#正确判断方法:
[[email protected] awk]# awk ‘BEGIN{tB["a"]="a1";tB["b"]="b1"; if("c" in tB){print "ok";}else{print "not in!"}; for(k in tB){print k,tB[k];}}‘
not in!
a a1
b b1
? if(key in array)通过这种方法判断数组中是否包含key键值。
#删除键值:
[[email protected] awk]# awk ‘BEGIN{tB["a"]="a1";tB["b"]="b1"; delete tB["a"]; for(k in tB){print k,tB[k];}}‘
b b1
? delete array[key]可以删除 对应数组key的序列值。
二维、多维数组使用
awk的多维数组在本质上是一维数组,更确切一点,awk在存储上并不支持多维数组。awk提供了逻辑上模拟二维数组的访问方式。例如:array[2,4]=1
这样的访问时允许的。awk使用一个特殊的字符串SUBSEP(?34)
作为分隔字段,在上面的例子中,关联数组array存储的键值实际上是2?344
。
类似一维数组的成员测试,多维数组可以使用if( (i,j) in array)
这样的语法,但是下标必须放置在圆括号中。类似一维数组的循环访问,多维数组使用for( item in array)
这样的语法遍历数组。与一维数组不同的是,多维数组必须使用split()
函数来访问单独的下标分量。
列出乘法口诀
#有序列出乘法口诀
awk ‘BEGIN{
for(i=1;i<=9;i++){
for(j=1;j<=9;j++){
tarr[i,j]=i*j;
print i,"*",j,"=",tarr[i,j];
}
}
}‘
运行结果:
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
......
9 * 9 = 81
? 可以通过array[k,k2]引用获得数组内容。
另一种方法:
#无序列出乘法口诀
awk ‘BEGIN{
for(i=1;i<=9;i++){
for(j=1;j<=9;j++){
tarr[i,j]=i*j;
}
}
for(m in tarr){
split(m,tarr2,SUBSEP);
print tarr2[1],"*",tarr2[2],"=",tarr[m];
}
}‘
运行结果:
8 * 7 = 56
9 * 1 = 9
8 * 8 = 64
......
8 * 6 = 48
内置函数
awk内置函数,主要分以下几种类:算术函数、字符串函数、其它一般函数、时间函数。
算术函数
格式 | 描述 |
---|---|
atan2()y,x | 返回y/x的反正切。 |
cos(x) | 返回x的余弦;x是弧度。 |
sin(x) | 返回x的正弦;x是弧度。 |
exp(x) | 返回x幂函数。 |
log(x) | 返回x的自然对数。 |
sqrt(x) | 返回x平方根。 |
int(x) | 返回x的截断至整数的值。其实就是输入小数返回一个整数。 |
rand( ) | 返回任意数字n,其中 0<=n<1。 |
srand([expr]) | 将rand函数的值设置为Expr参数的值,或如果省略Expr参数则使用某天的时间。返回先前的值。 |
举例说明:
[[email protected] awk]# awk ‘BEGIN{OFMT="%0.3f";fs=sin(1);fe=exp(10);fl=log(10);fi=int(3.1415);print fs,fe,fl,fi}‘
0.841 22026.466 2.303 3
OFMT 设置输出数据格式是保留3位小数。
获得随机数:
[[email protected] awk]# awk ‘BEGIN{srand();fr=int(100*rand());print fr;}‘
56
[[email protected] awk]# awk ‘BEGIN{srand();fr=int(100*rand());print fr;}‘
97
[[email protected] awk]# awk ‘BEGIN{srand();fr=int(100*rand());print fr;}‘
12
解读:脚本执行过程:
- rand() 随机返回一个六位小数点的小数,如:0.237788
- 然后是100rand(),就是100 0.237788 = 23.7788
- 通过int() 返回一个整数23。
- 再传给srant() 作为参数,处理,输出最后结果。
字符串函数
注:
Ere :可以是字符串、变量、也可以是正则表达式。
Repl:要替换成的值
In:是一个变量,或者字符串
格式 | 描述 |
---|---|
gsub(Ere,Repl,[ In ]) | 根据正则表达式替换所有匹配到的字符串,它和sub函数完全一样地执行,但是sub只替换从左往右第一次匹配到的字符串。 |
sub(Ere,Repl,[ In ]) | 根据正则表达式Ere匹配In中所包含的匹配内容替换成Repl,并将替换后的内容赋值给In。sub函数返回匹配替换的数量。出现在Repl参数指定的字符串中的&(和符号) 由In参数指定的Ere参数的指定的扩展正则表达式匹配的字符串替换。如果未指定In参数,缺省值是整个记录($0记录变量)。 |
index(String1,String2) | 判断string2是否出现在string1中,如果有返回位置,位置从1开始编号。如果String2参数不在String1参数中出现,则返回0。 |
length[(string)] | 返回string参数指定的字符串的长度(字符形式)。如果未给出string参数,则返回整个记录的长度($0记录变量)。 |
blength[(string)] | 返回string参数指定的字符串的长度(以字节为单位)。如果未给出string参数,则返回整个记录的长度($0记录变量)。 |
substr(string,M,[N]) | M:代表string里边的位置,M位置编号从1开始<br />N:代表要从M字符串的位置,往右取多少个值,包含M,但不包含M+N的和的值<br />命令意思:在string字符串中截取从 M位置开始取N个字符串,返回所取到的值。<br />如果未指定N参数,则代表截取从M位置到string参数的末尾位置,包含最后一个字符。 |
match(string,Ere) | 根据正则表达式Ere 在string中匹配查找,匹配到之后返回字符串所在位置,位置从1开始编号,或如果Ere参数不出现,则返回0。 RSTART特殊变量设置为返回值。RLENGTH特殊变量设置为匹配的字符串的长度,或如果未找到任何匹配,则设置为-1。 |
split(string,A,[Ere]) | 将string参数指定的参数分隔为数组元素A[1],A[2],...A[N],并返回n变量的值。此分隔可以通过Ere参数指定的扩展正则表达式进行,或用当前字段分隔符(FS特殊变量)来进行(如果没有给出Ere参数)。除非上下文指明特定的元素还应具有一个数字值,否则A数组中的元素用字符串值来创建。 |
tolower(string) | 将string字符串里边的大写字母都编程小写字母。 |
toupper(string) | 将string字符串里边的小写字母都变成大写字母。 |
sprintf(Format,Expr,Expr,...) | 根据Format参数指定的printf子例程格式字符串来格式化Expr参数指定的表达式并返回最后生成的字符串。 |
gsub,sub使用
#gsub替换所有匹配的字符串
[[email protected] awk]# awk ‘BEGIN{info="this is a test201test2010test!"; a=gsub(/[0-9]+/,"!",info); print a,info}‘
2 this is a test!test!test!
#sub只替换从左到右第一次匹配到的字符串
[[email protected] awk]# awk ‘BEGIN{info="this is a test201test2010test!"; a=gsub(/[0-9]+/,"!",info); print a,info}‘
2 this is a test!test!test!
#当没有匹配到的时候就返回原值。
[[email protected] awk]# awk ‘BEGIN{info="this is a testtesttest!"; a=gsub(/[0-9]+/,"!",info); print a,info}‘
0 this is a testtesttest!
在info中查找满足正则表达式 /[0-9]+/
用 " " 替换,并且替换后的值,赋值给info。如果没有匹配到未给info赋值,输出info的原值,默认替换数量为0。
查找字符串(index使用)
#查找如果test在info字符串中,就返回ok,不在返回no found
[[email protected] awk]# awk ‘BEGIN{info="this is a test2010test2010test!"; print index(info,"test")?"ok":"no found!";}‘
ok
#查找如果test在info字符串中,返回test所在的位置,位置从左往右 编号从1开始。
[[email protected] awk]# awk ‘BEGIN{info="this is a test2010test2010test!";b=index(info,"test");print b}‘
11
#匹配字符串,未找到返回0
[[email protected] awk]# awk ‘BEGIN{info="this is a test2010test2010test!";b=index(info,"Test");print b}‘
0
正则表达式匹配查找(match使用)
#匹配字符串,匹配到返回ok
[[email protected] awk]# awk ‘BEGIN{info="this is a test2010test2010test!";print match(info,/[0-9]+/)?"ok":"no found!";}‘
ok
#匹配到字符串,并返回字符串所在位置
[[email protected] awk]# awk ‘BEGIN{info="this is a test2010test2010test!";a=match(info,/[0-9]+/); print a}‘
15
#匹配不到返回0
[[email protected] awk]# awk ‘BEGIN{info="this is a testtesttest!";a=match(info,/[0-9]+/); print a}‘
0
截取字符串(substr使用)
#截取从M位置开始,向右取N个字符串
[[email protected] awk]# awk ‘BEGIN{info="this is a test2010test!";a=substr(info,11,8);print a}‘
test2010
#不指定N值,就截取从M到string末尾的值
[[email protected] awk]# awk ‘BEGIN{info="this is a test2010test!";print substr(info,11);}‘
test2010test!
字符串分隔(split使用)
[[email protected] awk]# awk ‘BEGIN{info="this is a test!"; split(info,aa," "); print length(aa); for(k in aa){print k,aa[k];}}‘
4
4 test!
1 this
2 is
3 a
分隔字符串info,动态创建数组aa,用空格“ ”分隔符 风格info;
通过length获取数组aa元素的总数,当然也可以直接split的时候赋值一个变量获取元素的总数。
for(key in array)循环数组,是一个无序的循环。并不是从数组下标1...n,因此使用需要注意。
格式化字符串输出(printf使用)
格式化字符串 格式:
格式化字符串包含两部分内容:一部分是正常字符,这些字符将按原样输出;另一部分是格式化规定字符,以"%"开始,后跟一个或几个规定字符,用来确定输出内容格式。
格式 | 描述 |
---|---|
%d | 十进制有符号整数 |
%u | 十进制无符号整数 |
%f | 浮点数 |
%s | 字符串 |
%c | 单个字符 |
%p | 指针的值 |
%e | 指数形式的浮点数 |
%X | %X 无符号以十六进制表示的整数 |
%o | 无符号以八进制表示的整数 |
%g | 自动选择合适的表示法 |
[[email protected] awk]# awk ‘BEGIN{n1=124.113; n2=-1.224; n3=1.2345; printf("%.2f,%.2u,%.2g,%X,%o
",n1,n2,n3,n1,n1);}‘
124.11,18446744073709551615,1.2,7C,174
一般函数
格式 | 描述 |
---|---|
close(Expression) | 用同一个字符串值Expression参数来关闭由 print或printf语句、打开或调用getline函数打开的文件或管道。如果文件或管道成功关闭,则返回0;其它情况下返回非0值。如果打算写一个文件,并稍后在同一个程序中读取文件,则close语句时必须的。 |
system(command) | 执行command 参数指定的命令,并返回退出状态。等同于system子进程。 |
Expression | getline [ Variable ] | 从来自Expression参数指定的命令的输出中 通过管道传送的流中读取一个输入记录,并将该记录的值指定给Variable参数指定的变量。如果当前未打开将Expression参数的值作为其命令名称的流,则创建流。创建的流等同于调用popen子进程,此时command参数取Expression参数的值且mode参数设置为一个是r的值。只要流保留打开且Expression参数求得同一个字符串,则对getline函数的每次后续调用读取另一个记录。如果未指定Variable参数,则$0记录变量和NF特殊变量设置为从流读取的记录。 |
getline [ Variable ] < Expression | 从Expression参数指定的文件读取输入的下一个记录,并将Variable参数指定的变量设置为该记录的值。只要流保留打开且Expression参数对同一个字符串求值,则对getline函数的每次后续调用读取另一个记录。如果未指定Variable参数,则$0记录变量和NF特殊变量设置为从流读取的记录。 |
getline [ Variable ] | 将Variable参数指定的变量设置为从当前输入文件读取的下一个输入记录。如果未指定Variable参数,则$0记录变量设置为该记录的值,还将设置NF、NR、FNR特殊变量。 |
打开外部文件(close用法)
[[email protected] awk]# awk ‘BEGIN{ while("cat /etc/passwd" | getline){print $0;}; close("/etc/passwd");}‘
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
逐行读取外部文件(getline使用方法)
[[email protected] awk]# awk ‘BEGIN{ while(getline < "/etc/passwd"){print $0;};close("/etc/passwd");}‘
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[[email protected] awk]# awk ‘BEGIN{print "Enter your name:";getline name;print name;}‘
Enter your name:
abc
abc
调用外部应用程序(system使用方法)
[[email protected] awk]# awk ‘BEGIN{b=system("ls -al"); print b;}‘
total 24
drwxr-xr-x. 2 root root 77 Apr 17 15:58 .
dr-xr-x---. 12 root root 4096 Apr 12 15:01 ..
-rw-r--r--. 1 root root 10 Apr 17 13:23 ceshi
-rw-r--r--. 1 root root 13 Apr 17 15:39 datafile
-rw-r--r--. 1 root root 13 Apr 17 15:40 datafile2
-rw-r--r--. 1 root root 16 Apr 12 15:03 test
-rw-r--r--. 1 root root 222 Apr 17 14:25 test2
0
# b 代表返回值,是执行结果。0代表执行成功,非0表示执行失败。
时间函数
格式 | 描述 |
---|---|
mktime( YYYY MM dd HH MM ss[DST]) | 生成时间格式 |
strftime([format [,timestamp]]) | 格式化时间输出,将时间戳转为时间字符串。具体格式见下表。 |
systime() | 得到时间戳,返回从1970年1月1日开始到当前时间(不计闰年)的整秒数 |
显示一个时间(mktime使用)
[[email protected] awk]# awk ‘BEGIN{tstamp=mktime("2018 04 19 10 27 30"); print strftime("%c",tstamp);}‘
Thu 19 Apr 2018 10:27:30 AM CST
%c 代表本地日期和时间格式。
#计算两个时间 时间差,差的单位为秒
[[email protected] awk]# awk ‘BEGIN{tstamp1=mktime("2018 04 19 10 0 0"); tstamp2=mktime("2018 04 19 11 0 0"); print tstamp2-tstamp1;}‘
3600
[[email protected] awk]# awk ‘BEGIN{tstamp1=mktime("2001 01 01 0 0 0"); tstamp2=systime(); print "从2001年01月1日0点到现在时间相差秒:"tstamp2-tstamp1;print strftime("%c",tstamp2)}‘
从2001年01月1日0点到现在时间相差秒:545827039
Thu 19 Apr 2018 10:37:19 AM CST
strftime日期和时间格式说明符
格式 | 描述 |
---|---|
%a | 星期几的缩写(Sun) |
%A | 星期几的完整写法(Sunday) |
%b | 月名的缩写(Oct) |
%B | 月名的完整写法(October) |
%c | 本地日期和时间 |
%d | 十进制日期 |
%D | 日期 08/20/99 |
%e | 日期,如果只有一位会补上一个空格 |
%H | 用十进制表示24小时格式的小时 |
%I | 用十进制表示12小时格式的小时 |
%j | 从1月1日起一年中的第几天 |
%m | 十进制表示的月份 |
%M | 十进制表示的分钟 |
%p | 12小时表示法(AM/PM) |
%S | 十进制表示的秒 |
%U | 十进制表示的一年中的第几个星期(星期天作为一个星期的开始) |
%w | 十进制表示的星期几(星期天是0) |
%W | 十进制表示的一年中的第几个星期(星期一作为一个星期的开始) |
%x | 重新设置本地日期(08/20/99)(月份/日期/年份) |
%X | 重新设置本地时间(12:00:00) |
%y | 两位数字表示的年(99) |
%Y | 当前月份 |
%Z | 时区(PDT) |
%% | 百分号(%) |
以上是关于第十九章 文本处理流编辑器:awk编程的主要内容,如果未能解决你的问题,请参考以下文章