Awk教程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Awk教程相关的知识,希望对你有一定的参考价值。

Awk教程​


一、awk 简介

awk是一种解释执行的编程语言,专门用来处理文本数据的。


二、awk工作流程:

Awk内部工作原理;AWK执行的流程非常简单:读( Read )、执 行( Execute )与重复( Repeat );下面是流程图:

Awk教程​_awk

Awk工作流程图


读( Read )AWK 从输入流(文件、管道或者标准输入)中读入一行然后将其存入内存中。

执行(Execute)对于每一行输入,所有的

重复(Repeate)一直重复上述两个过程直到文件结束。



awk程序结构

Awk程序结构主要包括三块:BEGIN(开始块)、主体块、END(结束块);


开始块(BEGIN BLOCK):

语法:

BEGINawk-commands

开始块就是awk程序启动时执行的代码部分(在处理输入流之前执行),并且在整个过程中只执行一次;一般情况下,我们在开始块中初始化一些变量。BEGIN是awk的关键字,因此必须要大写。【注:开始块部分是可选,即你的awk程序可以没有开始块部分】



主体块(Body Block):

语法:

/pattern/awk-commands

针对每一个输入的行都会执行一次主体部分的命令,默认情况下,对于输入的每一行,awk都会执行主体部分的命令,但是我可以使用/pattern/限制其在指定模式下。



结束块(END BLOCK):

语法:

ENDawk-commands

结束块是awk程序结束时执行的代码(在处理完输入流之后执行),END也是awk的关键字,必须大写,与开始块类似,结束块也是可选的。



示例1:

题目:有一个文本a.txt,内容如下:

1 zhengchengcheng math 100

2 wangbin chinese 80

3 wangcheng pgysical 85

4 lily english 75

5 mary history 90

使用awk将其标准输出并附带表头信息?


解答:

Awk教程​_awk_02




awk基本语法

Awk命令行模式:

一般情况下,我们使用awk命令行模式比较多,即直接使用awk命令处理文本数据;


Awk命令行格式如下:

awk [options] awk-commands file



Awk程序文件:

当然,除了直接使用awk命令来处理文本之外,我们还可以将awk命令写成脚本来执行,即awk程序文件。



Awk程序文件执行格式如下:

awk [options] -f file



Awk标准选项:

常用的awk选项如下:


-v:这个选项可以为变量赋值,它允许在程序执行之前为变量赋值【注:一般用法即在程序执行前为变量赋值】

例如:

执行结果如下:


Awk教程​_awk_03




--dump-variables[=file]:此选项会将awk全局变量及相应值按序输出到指定文件中,不指定文件,默认输出文件名是awkvars.out


执行结果如下:

awk --dump-variables=/tmp/xin 【注:’’引号不能少,不然会报错,代表awk主体部分;--dump-variables=/tmp/xin表示将内容输出到/tmp/xin文件中去】



Awk教程​_awk_04




--lint[=fatal]:这个选项用于检测程序的可移植情况以及代码中的可以部分,如果提供了参数fatal,awk会将所有的警告信息当错误信息输出。


例如:awk --lint /tmp/xin 【注:同样,强调一遍,主题部分不能省略,没处理命令使用’’代替即可,检测文件为/tmp/xin】


执行结果如下:


Awk教程​_awk_05





--profile[=file]:此选项会将程序文件以一种很优美的格式输出(常用来格式化awk脚本文件),默认输出文件是awkprof.out,[=file]表示将格式化后的脚本内容输出到指定文件。


例如:awk -F" " --profile=/tmp/awk.sh BEGINprintf "No\\tName\\t\\tCourse\\tGrade\\n\\n" print $0 ENDprint"\\n-----The End-----" a.txt 【注:使用awk格式化输出a.txt内容,并将命令以一种优美的方式输出到/tmp/awk.sh文件中去】


执行结果如下:


Awk教程​_awk_06




--version:显示awk版本信息。

命令:awk --version



-F:指定域分隔符。【用来分隔每条记录中各个域的】

例如:awk -F: print $1 /etc/passwd 【注:打印系统所有的用户;$1代表第一个域】

执行结果如下:


Awk教程​_awk_07




awk基本示例

我们以a.txt文件作为示例文件,a.txt文件内容如下:


Awk教程​_awk_08



打印列或域:

在awk中,对于输入流,输入的每行,叫做一条记录;每一条记录中以分隔符分隔的各个部分叫做域,awk每次载入一条记录进行处理,默认的分隔符为空格。


例如:打印出a.txt文件中姓名和成绩这两列,使用awk进行操作;


命令:awk -F" " print $2,$4 a.txt | column -t 【注:column -t是按比较美观的格式显示输出】

执行结果如下:


Awk教程​_awk_09



输出整行:

$0代表输出整条记录。


例如:输出姓名为wangbin的那行,用awk去实现?


命令:awk -F" " /wangbin/print $0 a.txt 【这条语句先用/pattern/去匹配,匹配到后在输出整行内容】


执行结果如下:



Awk教程​_awk_10


【注:如果没有主体块(即:print $0),则默认是输出记录(行)】



匹配模式输出指定的列(域):

例如:输出姓名为wangbin那行中的第1,2,4列,用awk实现?


命令:awk -F" " /wangbin/print $1,$2,$4 a.txt


执行结果如下:


Awk教程​_awk_11





计算匹配次数并输出:

例如:计算姓名以w开头的行的个数,用awk实现?


命令:

awk -F /w/++count END printf "count is: %d\\n",count a.txt


执行结果如下:


Awk教程​_awk_12





输出字符数多于33的行:

例如:打印输出字符串个数多于33的行,用awk实现?


命令:awk -F" " length($0) > 33print $0 a.txt

或者

awk -F" " length($0) > 33 a.txt

执行结果如下:


Awk教程​_awk_13



【注:length函数是awk的内置函数,该函数返回字符串的长度,变量$0表示整行,缺失的主体块会执行默认动作(打印输出);如果一行中的字符数超过33,则length($0) > 33为真,则打印输出,否则不打印】





awk内置变量

Awk提供了一些内置变量,在写脚本或实际运用中起到很重要的作用。


1、标准awk变量:

(1)ARGC

ARGC表示在命令行提供的参数的个数;【注:实际参数个数=ARGC -1,因为第一个参数永远是awk】


例如:awk BEGINprint "arguments = ",ARGC -1 xin ss ll w


执行结果如下:


Awk教程​_awk_14


【注:从上面可以看出,ARGC = 实际参数个数+1】



(2)ARGV

ARGV表示将命令行输出的参数存储为一个数组,ARGV即是这个数组的名称;数组的有效索引从0到ARGC-1;


例如:awk BEGINfor(i=0;i<ARGC;i++) printf "ARGV[%d] = %s\\n",i,ARGV[i] xin ss ll w 【这条命令是循环打印出所有参数】


执行结果如下:


Awk教程​_awk_15


【注:第一个参数永远是awk,索引号为0】



(3)ENVIRON

ENVIRON表示与环境变量相关的关联数组变量;【注:即使用这个内置变量可以查看当前系统环境下的环境变量设置,用法为ENVIRON[环境变量名]】


例如:

awk BEGINprint ENVIRON["SHELL"]

awk BEGINprint ENVIRON["PATH"]


执行结果如下:


Awk教程​_awk_16




(4)FILENAME

FILENAME表示当前文件名称;


例如:awk ENDprint FILENAME a.txt


执行结果如下:


Awk教程​_awk_17


【注:开始块中FILENAME未定义,因为BEGIN开始块是在文本处理操作之前执行的,所以FILENAME还没定义,该变量的值为空;一般用于END结束块,打印出当前文件名称】



(5)FS

FS表示输入时的域分隔符,其默认值是空格,可以使用-F参数指定与分隔符;


例如:awk BEGINprint "FS=" FS | cat -A


执行结果如下:


Awk教程​_awk_18


【注:cat -A是显示行结束标识符,linux默认是$;可以看出FS默认是空格】


也可以使用-F参数指定域分隔符;

例如:awk -F: BEGINprint "FS=" FS | cat -A


执行结果如下:


Awk教程​_awk_19


【注:上图显示FS变成了:】




(6)OFS

OFS表示输出时的域分隔符,其默认值也是空格;


例如:打印输出a.txt文件中的第2,3列,并改变与分隔符为--,使用awk实现;


命令:


执行结果如下:


Awk教程​_awk_20




(7)NF

NF代表当前输入记录中域的数量;


例如:匹配输出姓名为wangbin的行,并显示这行的域总数;


命令:awk -F" " /wangbin/printf "context: (%s)\\nNF: (%s)\\n",$0,NF a.txt | column -t


执行结果如下:


Awk教程​_awk_21





(8)NR

NR表示当前输入记录数(即行号);


例如:打印输出a.txt文件第2-4行(即1<NR<=4)的内容,用awk实现;


命令:awk -F" " if(NR<=4 && NR>1) print NR,$0 a.txt | column -t


执行结果如下:


Awk教程​_awk_22




(9)FNR

FNR也表示记录数(行号),与NR类似,但是不同在于它是相对于文件而言的,此变量在处理多个文件时有重要的作用,每当从新的文件读入时,FNR都会被重新置为0;


NR与FNR比较:


例如:现在有两个文件a.txt,b.txt,现在要求打印输出并添加行号,分别使用NR和FNR对比效果;


NR显示结果:


Awk教程​_awk_23


【注:如上图执行结果显示,NR是相对于整个输入流而言,行号不断从1开始递增,所以无法通过NR来区分多个文件】



FNR显示结果:


Awk教程​_awk_24



【注:如上图结果显示,FNR是相对于文件而言的,当读入新文件时,FNR会被重新置为0,即当一个文件结束,开始读入第二个文件时,行号重新从1开始递增,所以可以通过FNR来区分多个文件】



(10)RS

RS表示输入记录(行)分隔符【即输入时的记录分隔符】,默认是换行符,可以使用RS指定输入记录分隔符;


例如:echo "1,1--2,2--3,3--4,4--5,5" | awk -F"," BEGINRS="--"print $0


上面的语句:输入文本内容为"1,1--2,2--3,3--4,4--5,5",默认的记录分隔符为换行符,我们使用RS="--"指定记录分隔符为--后,awk主体程序就需要处理五条记录【这五条记录分别为:1,1、2,2、3,3、4,4、5,5】


执行结果如下:

Awk教程​_awk_25


【注:以上就是显示的结果,当然大家可能会发现为什么结尾会多一个空包行呢,print最后默认就会输出一个换行,这个可以不用理会】



(11)ORS

ORS表示输出记录(行)分隔符【即输出时的记录分隔符】,默认是换行符,可以使用ORS指定输出记录分隔符;


例如:a.txt文件不换行输出,并指定输出记录分隔符为||,用来区分原来的每一条记录,用awk实现;


命令:awk ORS=" || ";print $0 a.txt


执行结果如下:

Awk教程​_awk_26


【结果显示,已将换行符换成了||】



(12)RLENGTH

RLENGTH表示match函数匹配的字符串长度,awk的match函数用于在输入的字符串中搜索指定字符串;


例如:awk BEGINif(match("this is good","good"));print RLENGTH 【表示match函数在输入字符串中匹配good字符串,RLENGTH返回匹配到的good字符串的长度】


执行结果如下:


Awk教程​_awk_27





(13)RSTART

RSTART表示由match函数匹配的字符串的第一个字符的位置【注:是匹配字符串的第一个字符在所有输入的内容中的位置】;


例如:awk BEGINif(match("this is good","good"));print RSTART 【这表示match匹配到的good字符串中的第一个字符g在输入内容中this is good的位置】


执行结果如下:


Awk教程​_awk_28




  1. $0

$0表示输入的整个输入记录;



(15)$n

$n表示当前输入记录的第n个域,这些域之间由FS分隔,n的取值为1,2,3......;





awk特定变量(即专有变量)

(1)ARGIND

ARGIND表示当前文件中正在处理的ARGV数组的索引值;


例子:有三个文件分别是junk1、junk2、junk3,每个文件中都有两行;


命令:

执行结果如下:


Awk教程​_awk_29


【注:ARGIND其实就是每个文件的序列号,例如第一个文件是junk1,那么这时ARGIND=1,且会遍历该文件中所有行,有多少行就会输出多少个ARGIND=1(这变量生产中我一次也没用到过)】



ERRNO

ERRNO用于存储当getline重定向失败或者close函数调用失败时的失败信息;


例子:awk BEGINret=getline<"xin.t";if(ret==-1) print "error: ",ERRNO


执行结果如下:


Awk教程​_awk_30


【注:因为xin.t这个文件并不存在,报错,错误信息保存到了ERROR变量中】



IGNORECASE

IGNORECASE表示忽略大小写;


例如:找出a.txt文件中name=wangbin这一行;使用awk这一行


首先不开启,即IGNORECASE=0的情况(区分大小写):

执行结果如下:


Awk教程​_awk_31



开启IGNORECASE,即IGNORECASE=1的情况(忽略大小写):

执行结果如下:


Awk教程​_awk_32




TEXTDOMAIN

TEXTDOMAIN表示awk程序当前文本域,它主要是来寻找程序中字符串的本地翻译,用于程序的国际化;默认值是messages;


例如:


执行结果如下:


Awk教程​_awk_33






awk操作符

算数运算符

加法(+)

例子:awk BEGINa=5;b=3;printf "a + b = %d\\n",a+b

或者

awk BEGINa=5;b=3;print "a + b =",a+b


执行结果如下:

Awk教程​_awk_34



减法(-)

例子:awk BEGINa=5;b=3;printf "a - b = %d\\n",a-b

或者

awk BEGINa=5;b=3;print "a - b =",a-b


执行结果如下:


Awk教程​_awk_35



乘法(*)

例子:awk BEGINa=5;b=3;printf "a * b = %d\\n",a*b

或者

awk BEGINa=5;b=3;print "a * b =",a*b


执行结果如下:


Awk教程​_awk_36



除法(/)【awk除法可以保留精度】

例子:awk BEGINa=5;b=3;printf "a / b = %d\\n",a/b 【结果只保留整数】

【结果保留3位精度】

或者

【默认print输出保留5位精度】


执行结果如下:


Awk教程​_awk_37




(5)模运算符(%)【即取余运算】

例子:awk BEGINa=5;b=3;printf "a % b = %d\\n",a%b

或者

awk BEGINa=5;b=3;print "a % b =",a%b


执行结果如下:


Awk教程​_awk_38




递增运算符之前置递增运算(如++a)

例子:awk BEGINa=5;b=++a;printf "a = %d, b = %d\\n",a,b


执行结果如下:


Awk教程​_awk_39



【注:b=++a表示先执行递增操作,后执行赋值操作,即先执行a=a+1,在执行b=a,所以结果a和b都为6】




递增运算符之后置递增运算(如a++)

例子:awk BEGINa=5;b=a++;printf "a = %d, b = %d\\n",a,b


执行结果如下:


Awk教程​_awk_40


【注:b=a++表示先执行赋值操作,后执行递增操作,即先执行b=a,再执行a=a+1,所以结果a=6,b=5】


递减运算符之前置递减运算(如--a)

例子:awk BEGINa=5;b=--a;printf "a = %d, b = %d\\n",a,b


执行结果如下:


Awk教程​_awk_41


【注:b=--a表示先执行递减操作,后执行赋值操作,即先执行a=a-1,再执行b=a,所以结果a=4,b=4】


递减运算符之后置递减运算(如a--)

例子:awk BEGINa=5;b=a--;printf "a = %d, b = %d\\n",a,b


执行结果如下:


Awk教程​_awk_42


【注:b=a--表示先执行赋值操作,后执行递减操作,即先执行b=a,再执行a=a-1,所以结果a=4,b=5】



赋值运算符

简单赋值(=)

例子:awk BEGINname = "zx";printf "name = %s\\n",name


执行结果如下:


Awk教程​_awk_43将awk脚本写在文件里:一种高效的awk循环循环方式

Awk教程

使用awk命令循环查找并修改后输出。

如何提取for循环的主体? [复制]

awk教程

awk教程