推广 热搜: LabVIEW  控制  自动化  电子  自动  软件  sci  机器视觉  编程  视觉 

Linux shell编程之awk介绍

   日期:2018-05-14     浏览:81    评论:0    
核心提示:如果要格式化报文或从一个大的文本文件中抽取数据包,那么awk可以完成这些任务。它在文本浏览和数据的熟练使用上性能优异。整体
 如果要格式化报文或从一个大的文本文件中抽取数据包,那么awk可以完成这些任务。它在文本浏览和数据的熟练使用上性能优异。整体来说, awk是所有shell过滤工具中最难掌握的。awk本身作为一门编程语言并不是三言两语可以讲清楚的,在此仅仅列出一些常用的功能,方便以后查阅。
 
一. awk的功能
awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk。awk语言的最基本功能是在文件或字符串中基于指定规则来分解抽取信息,也可以基于指定的规则来输出数据。完整的awk脚本通常用来格式化文本文件中 的信息。
 
二.  三种方式调用awk
1) awk [opion] 'awk_script' input_file1 [input_file2 ...]
awk的常用选项option有;
① -F fs : 使用fs作为输入记录的字段分隔符,如果省略该选项,awk使用环境变量IFS的值
② -f filename : 从文件filename中读取awk_script
③ -v var=value : 为awk_script设置变量
2) 将awk_script放入脚本文件并以 #!/bin/awk -f 作为首行,给予该脚本可执行权限,然后在shell下通过键入该脚本的脚本名调用之。
3) 将所有的awk_script插入一个单独脚本文件,然后调用: awk -f awk脚本文件 input_file(s)
三. awk的运行过程
1) awk_script的组成:
① awk_script可以由一条或多条awk_cmd组成,两条awk_cmd之间一般以newline分隔
② awk_cmd由两部分组成: awk_pattern { actions }
③ awk_script可以被分成多行书写,必须确保整个awk_script被单引号括起来。
2) awk命令的一般形式:
awk ' BEGIN { actions }
awk_pattern1 { actions }
............
awk_patternN { actions }
END { actions }
' inputfile
其中 BEGIN { actions } 和 END { actions } 是可选的。
3) awk的运行过程:
① 如果BEGIN 区块存在,awk执行它指定的actions。
② awk从输入文件中读取一行,称为一条输入记录。(如果输入文件省略,将从标准输入读取)
③ awk将读入的记录分割成字段,将第1个字段放入变量$1中,第2个字段放入$2,以此类推。$0表示整条记录。字段分隔符使用shell环境变量IFS 或由参数指定。
④ 把当前输入记录依次与每一个awk_cmd中awk_pattern比较,看是否匹配,如果相匹配,就执行对应的actions。如果不匹配,就跳过对应 的actions,直到比较完所有的awk_cmd。
⑤ 当一条输入记录比较了所有的awk_cmd后,awk读取输入的下一行,继续重复步骤③和④,这个过程一直持续,直到awk读取到文件尾。
⑥ 当awk读完所有的输入行后,如果存在END,就执行相应的actions。
4) iput_file可以是多于一个文件的文件列表,awk将按顺序处理列表中的每个文件。
5) 一条awk_cmd的awk_pattern可以省略,省略时不对输入记录进行匹配比较就执行相应的actions。一条awk_cmd的actions 也可以省略,省略时默认的动作为打印当前输入记录(print $0) 。一条awk_cmd中的awk_pattern和actions不能同时省略。
6) BEGIN区块和END区块别位于awk_script的开头和结尾。awk_script中只有END区块或者只有BEGIN区块是被允许的。如果 awk_script中只有BEGIN { actions } ,awk不会读取input_file。
7) awk把输入文件的数据读入内存,然后操作内存中的输入数据副本,awk不会修改输入文件的内容。
8) awk的总是输出到标准输出,如果想让awk输出到文件,可以使用重定向。
四. awk的记录、字段与内置变量
awk处理的工作与数据库的处理方式有相同之处,其相同处之一就是awk支持对记录和字段的处理,其中对字段的处理是grep和sed不能实现的,这也是awk优于二者的原因之一。在awk中,缺省的情况下总是将文本文件中的一行视为一个记录,而将一行中的某一部分作为记录中的一个字段。为了操作这些不同的字段,awk借用shell的方法,用1,2,3...这样的方式来顺序地表示行(记录)中的不同字段。特殊地,awk用0表示整个行(记录)。不同的字段之间是用称作分隔符的字符分隔开的。系统默认的分隔符是空格或tab键。awk允许在命令行中用-F re的形式来改变这个分隔符。事实上,awk用一个内置的变量FS来记忆这个分隔符。awk中有好几个这样的内置变量,例如,记录分隔符变量RS、当前工作的记录数NR等等,本文后面的附表列出了全部的内置变 量。这些内置的变量可以在awk程序中引用或修改,例如,你可以利用NR变量在模式匹配中指定工作范围,也可以通过修改记录分隔符RS让一个特殊字符而不 是换行符作为记录的分隔符。 
 
例:显示文本文件myfile中第七行到第十五行中以字符%分隔的第一字段,第三字段和第七字段:
awk -F % 'NR==7,NR==15 {printf 1 3 7}'
 
常用的awk变量包括:
ARGC 命令行变元个数
ARGV 命令行变元数组
FILENAME 当前输入文件名
FNR 当前文件中的记录号
FS 输入域分隔符,默认为一个空格
RS 输入记录分隔符
NF 当前记录里域个数
NR 到目前为止记录数
OFS 输出域分隔符
ORS 输出记录分隔符
 
五.awk的内置函数
awk 之所以成为一种优秀的程序设计语言的原因之一是它吸收了某些优秀的程序设计语言(例如C)语言的许多优点。这 些优点之一就是内置函数的使用,awk定义并支持了一系列的内置函数,由于这些函数的使用,使得awk提供的功能更为完善和强大,例如,awk使用了一系 列的字符串处理内置函数(这些函数看起来与C 语言的字符串处理函数相似,其使用方式与C语言中的函数也相差无几),正是由于这些内置函数的使用,使 awk处理字符串的功能更加强大。本文后面的附录中列有一般的awk所提供的内置函数,这些内置函数也许与你的awk版本有些出入,因此,在使用之前,最好参考一下你的系统中的联机帮助。 
 
作为内置函数的一个例子,我们将在这里介绍awk的printf函数,这个函数使得awk与c语言的 输出相一致。实际上,awk中有许多引用形式都是从C语言借用过来的。如果你熟悉C语言,你也许会记得其中的printf函数,它提供的强大格式输出功能 曾经带我们许多的方便。幸运的是,我们在awk中又和它重逢了。awk中printf几乎与C语言中一模一样,如果你熟悉C语言的话,你完全可以照C语言 的模式使用awk中的printf。因此在这里,我们只给出一个例子,如果你不熟悉的话,请随便找一本C语言的入门书翻翻。 
 
例:显示文 件myfile中的行号和第3字段:
awk '{printf"%03d%s\n",NR,1}' myfile
 
常用的内置字符串函数有:
gsub(r,s):整个$0中用s替换r
gsub(r,s,t):整个t中用s替换r
index(s,t):返回s中字符串t的第一位置
length(s):返回字符串s的长度
match(s,r):测试s是否包含匹配r的字符串
split(s,a,fs):在fs上将s分割成a,其中a为数组
sprint(fmt,exp):返回fmt格式化后的exp
sub(r,s):用$0中最左边最长的的字串替换s
substr(s,p):返回字符串s中从p开始的后缀部分
substr(s,p,n):返回字符串s中从p开始的长度为n的后缀部分
 
六.在命令行使用awk
按照顺序,我们应当讲解awk程序设计的内容了,但在讲解之前,我们将用一些例子来对前面的知识进行回顾,这些例子 都是在命令行中使用的,由此我们可以知道在命令行中使用awk是多么的方便。这样做的原因一方面是为下面的内容作铺垫,另一方面是介绍一些解决简单问题的 方法,我们完全没有必要用复杂的方法来解决简单的问题----既然awk提供了较为简单的方法的话。
例:显示文本文件mydoc匹配 (含有)字符串"sun"的所有行。
awk '/sun/{print}' mydoc
由于显示整个记录(全行)是 awk的缺省动作,因此可以省略action项。
awk '/sun/' mydoc
例:下面是一个较为复杂的匹配 的示例:
awk '/[Ss]un/,/[Mm]oon/ {print}' myfile
它将显示第一个匹配 Sun或sun的行与第一个匹配Moon或moon的行之间的行,并显示到标准输出上。
例:下面的示例显示了内置变量和内置函数 length()的使用:
awk 'length(0)>80 {print NR}' myfile
该命令行将显示文本myfile中所有超过80个字符的行号,在这里,用0表示整个记录(行),同时,内置变量NR不使用标志符''。
例:作为一个较为实际的例子,我们假设要对UNIX中的用户进行安全性检查,方法是考察/etc下的passwd文件,检查其中的passwd字段(第二字段) 是否为"*",如不为"*",则表示该用户没有设置密码,显示出这些用户名(第一字段)。我们可以用如下语句实现:
#awk -F: '2=="" {printf("%s no password!\n",1' /etc/passwd
在这个示例中,passwd文件的字段分隔符是“:”,因此,必须用-F:来更改默认的字段分隔符,这个示例中也涉及到了内置函数printf的使用。
 
七.awk的变量
如同其它程序设计语言一样,awk允许在程序语言中设置变量,事实上,提供变量的功能是程序设计语言的其本要求,不提供变 量的程序设计语言本人还从未见过。
awk 提供两种变量,一种是awk内置的变量,这前面我们已经讲过,需要着重指出的是,与后面提到 的其它变量不同的是,在awk程序中引用内置变量不需要使用标志符""(回忆一下前面讲过的NR的使用)。awk提供的另一种变量是自定义变量。awk允 许用户在awk程序语句中定义并调用自已的变量。当然这种变量不能与内置变量及其它awk保留字相同,在awk中引用自定义变量必须在它前面加上标志 符""。与C语言不同的是,awk中不需要对变量进行初始化, awk根据其在awk中第一次出现的形式和上下文确定其具体的数据类型。当变量类型不确定 时,awk默认其为字符串类型。这里有一个技巧:如果你要让你的 awk程序知道你所使用的变量的明确类型,你应当在在程序中给它赋初值。在后面的实例 中,我们将用到这一技巧。
运算与判断:
作为一种程序设计语言所应具有的特点之一,awk支持多种运算,这些运算与C 语言提供的几本相同:如+、-、*、/、%等等,同时,awk也支持C语言中类似++、--、+=、-=、=+、=-之类的功能,这给熟悉C语言的使用者 编写awk程序带来了极大的方便。作为对运算功能的一种扩展,awk还提供了一系列内置的运算函数(如log、sqr、cos、sin等等)和一些用于对 字符串进行操作(运算)的函数(如length、substr等等)。这些函数的引用大大的提高了awk的运算功能。
作为对条件转移指 令的一部分,关系判断是每种程序设计语言都具备的功能,awk也不例外。awk 中允许进行多种测试,如常用的==(等于)、!=(不等于)、& gt;(大于)、<(小于)、>=(大于等于)、>=(小于等于)等等,同时,作为样式匹配,还提供了~(匹配于)和!~(不匹配于) 判断。
作为对测试的一种扩充,awk也支持用逻辑运算符:!(非)、&&(与)、||(或)和括号()进行多重判断, 这大大增强了awk的功能。本文的附录中列出了awk所允许的运算、判断以及操作符的优先级。
 
八.awk的流程控制
流程控制语句是任何程序设计语言都不能缺少的部分。任何好的语言都有一些执行流程控制的语句。awk提供的完备的流程 控制语句类似于C语言,这给我们编程带来了极大的方便。
1、BEGIN和END:
在awk 中两个特别的表达 式,BEGIN和END,这两者都可用于pattern中(参考前面的awk语法),提供BEGIN和END的作用是给程序赋予初始状态和在程序结束之后 执行一些扫尾的工作。任何在BEGIN之后列出的操作(在{}内)将在awk开始扫描输入之前执行,而END之后列出的操作将在扫描完全部的输入之后执 行。因此,通常使用BEGIN来显示变量和预置(初始化)变量,使用END来输出最终结果。
例:累计销售文件xs中的销售金额(假设销 售金额在记录的第三字段):
awk 
>'BEGIN { FS=":";print "统计销售金额"; total=0} 
>{print 3;total=total+3;} 
>END {printf "销售金额总 计:%.2f",total}' sx 
(注:>是shell提供的第二提示符,如要在shell程序awk语句和awk语言中换行,则需 在行尾加反斜杠\)
在这里,BEGIN预置了内部变量FS(字段分隔符)和自定义变量total,同时在扫描之前显示出输出行头。而 END则在扫描完成后打印出总合计。
2、流程控制语句 
awk提供了完备的流程控制语句,其用法与C语言类似。下面我们一一加 以说明:
2.1、if...else语句:
格式: 
if(表达式) 
语句1 
else 
语 句2
格式中"语句1"可以是多个语句,如果你为了方便awk判断也方便你自已阅读,你最好将多个语句用{}括起来。awk分枝结构允许 嵌套,其格式为:
if(表达式1)
{if(表达式2) 
语句1 
else 
语句2 
语 句3 
else {if(表达式3) 
语句4 
else 
语句5 
语句6
当然实 际操作过程中你可能不会用到如此复杂的分枝结构,这里只是为了给出其样式罢了。
2.2、while语句
格式为:
while(表 达式) 
语句
2.3、do-while语句
格式为:
do 
语句 
}while(条 件判断语句)
2.4、for语句
格式为:
for(初始表达式;终止条件;步长表达式) 
{语 句}
在awk 的 while、do-while和for语句中允许使用break,continue语句来控制流程走向,也允许使用 exit这样的语句来退出。break 中断当前正在执行的循环并跳到循环外执行下一条语句。continue从当前位置跳到循环开始处执行。对于 exit的执行有两种情况:当exit语句不在 END中时,任何操作中的exit命令表现得如同到了文件尾,所有模式或操作执行将停止,END模式中的 操作被执行。而出现在END中的exit将导致程序终止。
例:为了awk中的自定义函数
定义和调 用用户自己的函数是几乎每个高级语言都具有的功能,awk也不例外,但原始的awk并不提供函数功能,只有在nawk或较新的awk版本中才可以增加函 数。
函数的使用包含两部分:函数的定义与函数调用。其中函数定义又包括要执行的代码(函数本身)和从主程序代码传递到该函数的临时调 用。
awk函数的定义方法如下:
function 函数名(参数表){ 
函数体 
}
在 gawk中允许将function省略为func,但其它版本的awk不允许。函数名必须是一个合法的标志符,参数表中可以不提供参数(但在调用函数时函 数名后的一对括号仍然是不可缺少的),也可以提供一个或多个参数。与C语言相似,awk的参数也是通过值来传递的。
在awk 中调用函 数比较简单,其方法与C语言相似,但awk比C语言更为灵活,它不执行参数有效性检查。换句话说,在你调用函数时,可以列出比函数预计(函数定义中规定) 的多或少的参数,多余的参数会被awk所忽略,而不足的参数,awk将它们置为缺省值0或空字符串,具体置为何值,将取决于参数的使用方式。
awk 函数有两种返回方式:隐式返回和显式返回。当awk执行到函数的结尾时,它自动地返回到调用程序,这是函数是隐式返回的。如果需要在结束之前退出函数,可 以明确地使用返回语句提前退出。方法是在函数中使用形如:return 返回值 格式的语句。
例:下面的例子演示了函数的使用。在这个 示例中,定义了一个名为print_header的函数,该函数调用了两个参数FileName和PageNum, FileName参数传给函数当前使 用的文件名,PageNum参数是当前页的页号。这个函数的功能是打印(显示)出当前文件的文件名,和当前页的页号。完成这个功能后,这个函数将返回下一 页的页号。 
 
nawk 
>'BEGIN{pageno=1;file=FILENAME 
>pageno=print_header(file,pageno);# 调用函数print_header 
>printf("当前页页号是:%d\n",pageno); 
>} 
 
># 定义函数print_header 
>function print_header(FileName,PageNum){ 
>printf("%s %d\n",FileName,PageNum); >PageNum++;return PageNUm; 
>} 
>}' myfile
执 行这个程序将显示如下内容:
myfile 1 
当前页页号是:2
awk高级输入输出
1. 读取下一条记录:
awk的next语句导致awk读取下一个记录并完成模式匹配,然后立即执行相应的操作。通常它用匹配的模式执行操作 中的代码。next导致这个记录的任何额外匹配模式被忽略。
2.简单地读取一条记录
awk 的 getline语句 用于简单地读取一条记录。如果用户有一个数据记录类似两个物理记录,那么getline将尤其有用。它完成一般字段的分离(设置字段变量 0 FNR NF NR)。如果成功则返回1,失败则返回0(到达文件尾)。如果需简单地读取一个文件,则可以编写以下代码:
例:示例 getline的使用
{while(getline==1) 
#process the inputted fields 
}
也 可以使getline保存输入数据在一个字段中,而不是通过使用getline variable的形式处理一般字段。当使用这种方式时,NF被置成 0,FNR和NR被增值。
用户也可以使用getline<"filename"方式从一个给定的文件中输入数据,而不是从命令行 所列内容输入数据。此时,getline将完成一般字段分离(设置字段变量0和NF)。如果文件不存在,返回-1,成功,返回1,返回0表示失败。用户可 以从给定文件中读取数据到一个变量中,也可以用stdin(标准输入设备)或一个包含这个文件名的变量代替filename。值得注意的是当使用这种方式 时不修改FNR和NR。
另一种使用getline语句的方法是从UNIX命令接受输入,例如下面的例子:
例:示例从 UNIX命令接受输入
{while("who -u"|getline) 
#process each line from the who command 
}
当然,也可以使用如下形式:
"command" | getline variable
3.关闭文件:
awk 中允许在程序中关闭一个输入或输出文件,方法是使用awk的close语句。
close("filename")
filename可以是getline打开的文件(也可以是 stdin,包含文件名的变量或者getline使用的确切命令)。或一个输出文件(可以是stdout,包含文件名的变量或使用管道的确切命令)。
4. 输出到一个文件:
awk中允许用如下方式将结果输出到一个文件:
printf("hello word!\n")>"datafile" 
或 printf("hello word!\n")>>"datafile"
5.输出到一个命令
awk 中允许用如下方式将结果输出到一个命令:
printf("hello word!\n")|"sort-t','"
 
打赏
 
更多>同类编程
0相关评论

推荐图文
推荐编程
点击排行

网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报