《UNIX AWK使用手册》是我几个月前的作品了,回过头来看,这篇文章实在是很粗燥,因当时我写作并上传这个作品时实在是太忙了,没有对文章的质量进行很好的检查,心里老觉得有愧于网友的厚爱,于是趁闲赶忙重写一遍,虽然不一定会有很大的改观,但质量是肯定要好一点的,唯如此,我的良心上才好受一点,呶,下面就是我的修改稿,各位老友请与第一版相比一下,看是否有所进步! 这次改写仍然保留了原有的风格:正文由浅入深,文后附上了大量的相关资料,这样做的原因是为了满足各种用户的需求,这在第一版中已经说过了。这次主要的改变是在内容上,加入了很多新内容,并增加了示例,以帮助读者理解其中的内容,附录也补充了许多新的资料。当然读者要真正地掌握awk,仅仅读了本文是不够的,还必须有上机实习这一步。值得提醒大家的是,awk有很多版本,并且各个版本之间存在着一些差别,因此,在使用awk以前最好参考一下你使用的系统的联机帮助。 什么是awk? 你可能对UNIX比较熟悉,但你可能对awk很陌生,这一点也不奇怪,的确,与其优秀的功能相比,awk还远没达到它应有的知名度。awk是什么?与其它大多数UNIX命令不同的是,从名字上看,我们不可能知道awk的功能:它既不是具有独立意义的英文单词,也不是几个相关单词的缩写。事实上,awk是三个人名的缩写,他们是:Aho、(Peter)Weinberg和(Brain)Kernighan。正是这三个人创造了awk---一个优秀的样式扫描与处理工具。 AWK的功能是什么?与sed和grep很相似,awk是一种样式扫描与处理工具。但其功能却大大强于sed和grep。awk提供了极其强大的功能:它几乎可以完成grep和sed所能完成的全部工作,同时,它还可以可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上,awk的确拥有自己的语言:awk程序设计语言,awk的三位创建者已将它正式定义为:样式扫描和处理语言。 为什么使用awk? 即使如此,你也许仍然会问,我为什么要使用awk? 使用awk的第一个理由是基于文本的样式扫描和处理是我们经常做的工作,awk所做的工作有些象数据库,但与数据库不同的是,它处理的是文本文件,这些文件没有专门的存储格式,普通的人们就能编辑、阅读、理解和处理它们。而数据库文件往往具有特殊的存储格式,这使得它们必须用数据库处理程序来处理它们。既然这种类似于数据库的处理工作我们经常会遇到,我们就应当找到处理它们的简便易行的方法,UNIX有很多这方面的工具,例如sed 、grep、sort以及find等等,awk是其中十分优秀的一种。 使用awk的第二个理由是awk是一个简单的工具,当然这是相对于其强大的功能来说的。的确,UNIX有许多优秀的工具,例如UNIX天然的开发工具C语言及其延续C++就非常的优秀。但相对于它们来说,awk完成同样的功能要方便和简捷得多。这首先是因为awk提供了适应多种需要的解决方案:从解决简单问题的awk命令行到复杂而精巧的awk程序设计语言,这样做的好处是,你可以不必用复杂的方法去解决本来很简单的问题。例如,你可以用一个命令行解决简单的问题,而C不行,即使一个再简单的程序,C语言也必须经过编写、编译的全过程。其次,awk本身是解释执行的,这就使得awk程序不必经过编译的过程,同时,这也使得它与shell script程序能够很好的契合。最后,awk本身较C语言简单,虽然awk吸收了C语言很多优秀的成分,熟悉C语言会对学习awk有很大的帮助,但awk本身不须要会使用C语言――一种功能强大但需要大量时间学习才能掌握其技巧的开发工具。 使用awk的第三个理由是awk是一个容易获得的工具。与C和C++语言不同,awk只有一个文件(/bin/awk),而且几乎每个版本的UNIX都提供各自版本的awk,你完全不必费心去想如何获得awk。但C语言却不是这样,虽然C语言是UNIX天然的开发工具,但这个开发工具却是单独发行的,换言之,你必须为你的UNIX版本的C语言开发工具单独付费(当然使用D版者除外),获得并安装它,然后你才可以使用它。 基于以上理由,再加上awk强大的功能,我们有理由说,如果你要处理与文本样式扫描相关的工作,awk应该是你的第一选择。在这里有一个可遵循的一般原则:如果你用普通的shell工具或shell script有困难的话,试试awk,如果awk仍不能解决问题,则便用C语言,如果C语言仍然失败,则移至C++。 awk的调用方式 前面曾经说过,awk提供了适应多种需要的不同解决方案,它们是: 一、awk命令行,你可以象使用普通UNIX命令一样使用awk,在命令行中你也可以使用awk程序设计语言,虽然awk支持多行的录入,但是录入长长的命令行并保证其正确无误却是一件令人头疼的事,因此,这种方法一般只用于解决简单的问题。当然,你也可以在shell script程序中引用awk命令行甚至awk程序脚本。 二、使用-f选项调用awk程序。awk允许将一段awk程序写入一个文本文件,然后在awk命令行中用-f选项调用并执行这段程序。具体的方法我们将在后面的awk语法中讲到。 三、利用命令解释器调用awk程序:利用UNIX支持的命令解释器功能,我们可以将一段awk程序写入文本文件,然后在它的第一行加上: #!/bin/awk -f 并赋予这个文本文件以执行的权限。这样做之后,你就可以在命令行中用类似于下面这样的方式调用并执行这段awk程序了。 $awk脚本文本名待处理文件 awk的语法: 与其它UNIX命令一样,awk拥有自己的语法: awk [ -F re] [parameter...] ['prog'] [-f progfile][in_file...] 参数说明: -F re:允许awk更改其字段分隔符。 parameter: 该参数帮助为不同的变量赋值。 'prog': awk的程序语句段。这个语句段必须用单拓号:'和'括起,以防被shell解释。这个程序语句段的标准形式为: 'pattern {action}' 其中pattern参数可以是egrep正则表达式中的任何一个,它可以使用语法/re/再加上一些样式匹配技巧构成。与sed类似,你也可以使用","分开两样式以选择某个范围。关于匹配的细节,你可以参考附录,如果仍不懂的话,找本UNIX书学学grep和sed(本人是在学习ed时掌握匹配技术的)。action参数总是被大括号包围,它由一系统awk语句组成,各语句之间用";"分隔。awk解释它们,并在pattern给定的样式匹配的记录上执行其操作。与shell类似,你也可以使用“#”作为注释符,它使“#”到行尾的内容成为注释,在解释执行时,它们将被忽略。你可以省略pattern和action之一,但不能两者同时省略,当省略pattern时没有样式匹配,表示对所有行(记录)均执行操作,省略action时执行缺省的操作――在标准输出上显示。 -f progfile:允许awk调用并执行progfile指定有程序文件。progfile是一个文本文件,他必须符合awk的语法。 in_file:awk的输入文件,awk允许对多个输入文件进行处理。值得注意的是awk不修改输入文件。如果未指定输入文件,awk将接受标准输入,并将结果显示在标准输出上。awk支持输入输出重定向。 awk的记录、字段与内置变量: 前面说过,awk处理的工作与数据库的处理方式有相同之处,其相同处之一就是awk支持对记录和字段的处理,其中对字段的处理是grep和sed不能实现的,这也是awk优于二者的原因之一。在awk中,缺省的情况下总是将文本文件中的一行视为一个记录,而将一行中的某一部分作为记录中的一个字段。为了操作这些不同的字段,awk借用shell的方法,用$1,$2,$3...这样的方式来顺序地表示行(记录)中的不同字段。特殊地,awk用$0表示整个行(记录)。不同的字段之间是用称作分隔符的字符分隔开的。系统默认的分隔符是空格。awk允许在命令行中用-F re的形式来改变这个分隔符。事实上,awk用一个内置的变量FS来记忆这个分隔符。awk中有好几个这样的内置变量,例如,记录分隔符变量RS、当前工作的记录数NR等等,本文后面的附表列出了全部的内置变量。这些内置的变量可以在awk程序中引用或修改,例如,你可以利用NR变量在模式匹配中指定工作范围,也可以通过修改记录分隔符RS让一个特殊字符而不是换行符作为记录的分隔符。 例:显示文本文件myfile中第七行到第十五行中以字符%分隔的第一字段,第三字段和第七字段: awk -F % 'NR==7,NR==15 {printf $1 $3 $7}' 虽然很简单的内容,但是还是纪录下来,这些很基础的东西必须的了解其含义。 AWK的內建變數(Built-in Variables) AWK 提供了許多內建變數, 使用者於程式中可使用這些變數 來取得相關資訊.常見的內建變數有 : 內建變數 涵意 NF (Number of Fields)為一整數, 其值表$0上所存在的欄位數目. NR (Number of Records)為一整數, 其值表AWK已讀入的資料列數目. FILENAMEAWK正在處理的資料檔檔名. 例如 : AWK 從資料檔 emp.dat 中讀入第一筆資料列 "A125 Jenny 100 210" 之後, 程式中: $0 之值將是 "A125 Jenny 100 210" $1 之值為 "A125" $2 之值為 "Jenny" $3 之值為 100 $4 之值為 210 NF 之值為 4 $NF 之值為 210 NR 之值為 1 FILENAME 之值為 ``emp.dat'' 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 ",NR,$1}' myfile 在命令行使用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! ",$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中允许进行多种测试,如常用的==(等于)、!=(不等于)、>(大于)、=(大于等于)、>=(小于等于)等等,同时,作为样式匹配,还提供了~(匹配于)和!~(不匹配于)判断。 作为对测试的一种扩充,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 ",pageno); >} >#定义函数print_header >function print_header(FileName,PageNum){ >printf("%s %d ",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"datafile" 或 printf("hello word! ")>>"datafile" 5.输出到一个命令 awk中允许用如下方式将结果输出到一个命令: printf("hello word! ")|"sort-t','" ----------------------------------------------------------------------------- awk中的基本单位: 1.Number(数字) decimal integers or floating-point quantities 如:789 3.141592654 +67 +4.6E3 -34 -2.1e-2 2.STRING(字符串) 任何被双引号引起的都是string(包括双引号)如: “one" "fesrf" "esf" 如果不包括双引号的话,就是“变量”如: one a c d 3.VARIABLE(变量) 4.regex (正则表达式) 正则表达式要被双斜杠包起来,如:/one/ /o.*/ 这些/one/ /o.*/,我们称之为regexp constant 5.Dynamic Regexps(正则表达式变量) [newadm@mail tmp]$ more test.txt one two three [newadm@mail tmp]$ awk 'BEGIN{A="one"}$0 ~ A{print}' test.txt one 这里面的A就是Dynamic Regexp,当awk执行$0 ~ A时候,效果跟$0 ~ /one/是一样的 因为A是Dynamic Regexp,所以不能写为$0 ~ /A/ 因为$0 ~ /A/ 表示的意思是:匹配任何含有大写字母A的行 [newadm@mail tmp]$ awk 'BEGIN{A="one"}{gsub(A,"111");print}'test.txt 111 two three 同样道理gsub(A,"111")这里面的A也是Dynamic Regexps, 以上的意思就是把任何行中的one改为111 如果改为gsub(/A/,"111")的话,意思就是:把行中的大写字母A,改给111 例子: [new@tmp]$ more test.txt one two three [new@tmp]$ awk 'BEGIN{A="one"}{gsub(A,"111");print}' test.txt 111 two three [new@tmp]$ awk '/one/{print }' test.txt one [new@tmp]$ awk 'BEGIN{A="one"}$0 ~ A{print}' test.txt one [new@tmp]$ awk 'BEGIN{A="one"}A{print}' test.txt one two three [root@/tmp]# awk 'BEGIN{A=one}$0 ~ A{print}' test.txt one two three A=one表示把变量one的值赋给变量A,但是one的值为空,所以$0 ~ A恒成立 [root@tmp]# [root@/tmp]# awk 'BEGIN{A="one"}$0 ~ A{print}' test.txt one A="one"表示把字符串one赋给变量A,$0 ~ A表示匹配任何含有one字符的行 [new@tmp]$ awk 'BEGIN{A="one"}/A/{print}' test.txt [new@tmp]$ --------------------------------------------------------------- 把shell变量传给awk有3种方式: 1.利用shell cmdline的特性 A=123 awk '/^'"$A"'/ { print $2 }' 上面的cmdline中,shell把'/^'"$A"'/ { print $2 }'作为awk的第一个参数,这个'/^'"$A"'/ { print $2 }'可以分为3小块 (1)'/^':因为/^被单引号引起来,所以shell传这个小部分给awk时候,传的是:/^ (2)"$A":因为$A是被双引号引起,所以shell传这个小部分给awk时候,先把$A,做给“变量替换”,所以传的是:123 (3)'/ { print $2 }':因为/ { print $2 }被单引起来,所以传的是:/ { print $2 } 这3个小部分做为一个参数传给awk,合计3个小部分,那么传的就是 /^123/ { print $2 } 2.使用-v参数 A=123 awk -v B="$A" '/^B/ { print $2 }' 3.pass variable settings into awk as "fake file names" awk '/^B/ { print $2 }' B="$A" ------------------------------------------------------------------------------ awk中使用的shell命令,有2种方法: 一。使用system() 二。使用print cmd | “/bin/bash” http://www.gnu.org/software/gawk/manual/gawk.html#I_002fO-Functions 一。使用所以system() awk程序中我们可以使用system() 函数去调用shell命令 如:awk 'BEGIN{system("echo abc")}' file echo abc 就会做为“命令行”,由shell来执行,所以我们会得到以下结果: root@ubuntu:~# awk 'BEGIN{system("echo abc")}' abc root@ubuntu:~# root@ubuntu:~# awk 'BEGIN{v1="echo";v2="abc";system(v1" "v2)}' abc root@ubuntu:~# root@ubuntu:~# awk 'BEGIN{v1="echo";v2="abc";system(v1 v2)}' /bin/sh: echoabc: command not found root@ubuntu:~# root@ubuntu:~# awk 'BEGIN{v1=echo;v2=abc;system(v1" "v2)}' root@ubuntu:~# 从上面的例子,我们简单的分析一下awk是怎样调用system的: 如果system()括号里面的参数没有加上双引号的话,awk认为它是一个变量,它会从awk的变量里面把它们先置换为常量,然后再回传给shell 如果system()括号里面的参数有加上双引号的话,那么awk就直接把引号里面的内容回传给shell,作为shell的“命令行” 二。使用print cmd | “/bin/bash” root@ubuntu:~# awk 'BEGIN{print "echo","abc"| "/bin/bash"}' abc root@ubuntu:~# root@ubuntu:~# awk 'BEGIN{print "echo","abc",";","echo","123"| "/bin/bash"}' abc 123 root@ubuntu:~# 三。总结 无论使用system()还是print cmd | “/bin/bash” awk都是新开一个shell,在相应的cmdline参数送回给shell,所以要注意当前shell变量与新开shell变量问题 1.1 root@ubuntu:~# abc=12345567890 root@ubuntu:~# awk 'BEGIN{system("echo $abc")}' root@ubuntu:~# 1.2 root@ubuntu:~# export abc=12345567890 root@ubuntu:~# awk 'BEGIN{system("echo $abc")}' 12345567890 root@ubuntu:~# 2.1 root@ubuntu:~# abc=1234567890 root@ubuntu:~# awk 'BEGIN{print "echo","$abc"| "/bin/bash"}' root@ubuntu:~# 2.2 root@ubuntu:~# export abc=1234567890 root@ubuntu:~# awk 'BEGIN{print "echo","$abc"| "/bin/bash"}' 1234567890 root@ubuntu:~# 以上例子,没有export的话,那些变量都是只存在于当前shell变量中,所以都是echo不出来的, 而使用了 export的都是环境变量,所以awk调用新的shell时候,可以echo出来 -------------------------------------------------------- awk用法小结: QUOTE: awk 用法:awk ' pattern {action} ' 变量名含义 ARGC 命令行变元个数 ARGV 命令行变元数组 FILENAME 当前输入文件名 FNR 当前文件中的记录号 FS 输入域分隔符,默认为一个空格 RS 输入记录分隔符 NF 当前记录里域个数 NR 到目前为止记录数 OFS 输出域分隔符 ORS 输出记录分隔符 1、awk '/101/' file 显示文件file中包含101的匹配行。 awk '/101/,/105/' file awk '$1 == 5' file awk '$1 == "CT"' file 注意必须带双引号 awk '$1 * $2 >100 ' file awk '$2 >5 && $21000000 ' 通过管道符获得输入,如:显示第4个域满足条件的行。 4、awk -F "|" '{print $1}' file 按照新的分隔符“|”进行操作。 awk 'BEGIN { FS="[: \t|]" } {print $1,$2,$3}' file 通过设置输入分隔符(FS="[: \t|]")修改输入分隔符。 Sep="|" awk -F $Sep '{print $1}' file 按照环境变量Sep的值做为分隔符。 awk -F '[ :\t|]' '{print $1}' file 按照正则表达式的值做为分隔符,这里代表空格、:、TAB、|同时做为分隔符。 awk -F '[][]' '{print $1}' file 按照正则表达式的值做为分隔符,这里代表[、] 5、awk -f awkfile file 通过文件awkfile的内容依次进行控制。 cat awkfile /101/{print "\047 Hello! \047"} --遇到匹配行以后打印 ' Hello! '.\047代表单引号。 {print $1,$2} --因为没有模式控制,打印每一行的前两个域。 6、awk '$1 ~ /101/ {print $1}' file 显示文件中第一个域匹配101的行(记录)。 7、awk 'BEGIN { OFS="%"} {print $1,$2}' file 通过设置输出分隔符(OFS="%")修改输出格式。 8、awk 'BEGIN { max=100 ;print "max=" max} BEGIN 表示在处理任意行之前进行的操作。 {max=($1 >max ?$1:max); print $1,"Now max is "max}' file 取得文件第一个域的最大值。 (表达式1?表达式2:表达式3 相当于: if (表达式1) 表达式2 else 表达式3 awk '{print ($1>4 ? "high "$1: "low "$1)}' file 9、awk '$1 * $2 >100 {print $1}' file 显示文件中第一个域匹配101的行(记录)。 10、awk '{$1 == 'Chi' {$3 = 'China'; print}' file 找到匹配行后先将第3个域替换后再显示该行(记录)。 awk '{$7 %= 3; print $7}' file 将第7域被3除,并将余数赋给第7域再打印。 11、awk '/tom/ {wage=$2+$3; printf wage}' file 找到匹配行后为变量wage赋值并打印该变量。 12、awk '/tom/ {count++;} END {print "tom was found "count" times"}' file END表示在所有输入行处理完后进行处理。 13、awk 'gsub(/\$/,"");gsub(/,/,""); cost+=$4; END {print "The total is $" cost>"filename"}' file gsub函数用空串替换$和,再将结果输出到filename中。 1 2 3 $1,200.00 1 2 3 $2,300.00 1 2 3 $4,000.00 awk '{gsub(/\$/,"");gsub(/,/,""); if ($4>1000&&$42000&&$43000&&$43000&&$43000) next; else c4+=$4; } END {printf "c4=[%d]\n",c4}"' file 通过next在某条件时跳过该行,对下一行执行操作。 14、awk '{ print FILENAME,$0 }' file1 file2 file3>fileall 把file1、file2、file3的文件内容全部写到fileall中,格式为 打印文件并前置文件名。 15、awk ' $1!=previous { close(previous); previous=$1 } {print substr($0,index($0," ") +1)>$1}' fileall 把合并后的文件重新分拆为3个文件。并与原文件一致。 16、awk 'BEGIN {"date"|getline d; print d}' 通过管道把date的执行结果送给getline,并赋给变量d,然后打印。 17、awk 'BEGIN {system("echo \"Input your name:\\c\""); getline d;print "\nYour name is",d,"\b!\n"}' 通过getline命令交互输入name,并显示出来。 awk 'BEGIN {FS=":"; while(getline0) { if($1~"050[0-9]_") print $1}}' 打印/etc/passwd文件中用户名包含050x_的用户名。 18、awk '{ i=1;while(i28) flag=1; if ((j==4||j==6||j==9||j==11)&&i>30) flag=1; if (flag==0) {printf "%02d%02d ",j,i} } } }' 19、在awk中调用系统变量必须用单引号,如果是双引号,则表示字符串 Flag=abcd awk '{print '$Flag'}' 结果为abcd awk '{print "$Flag"}' 结果为$Flag |