文本处理三剑客之awk(原创)

文本处理三剑客之awk(原创)

AWK是一种优良的文本处理工具,LinuxUnix环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯(Alfred Aho)、彼得·溫伯格(Peter Jay Weinberger)和布萊恩·柯林漢(Brian Wilson Kernighan)姓氏的首个字母)的最大功能取决于一个人所拥有的知识。AWK提供了极其强大的功能:可以进行正则表达式的匹配,样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上AWK的确拥有自己的语言:AWK程序设计语言,三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。gawkAWKGNU版本。最简单地说,AWK是一种用于处理文本的编程语言工具。AWK在很多方面类似于Unix shell编程语言,尽管AWK具有完全属于其本身的语法。它的设计思想来源于SNOBOL4sedMarc Rochkind设计的有效性语言、语言工具yacclex,当然还从C语言中获取了一些优秀的思想。在最初创造AWK时,其目的是用于文本处理,并且这种语言的基础是,只要在输入数据中有模式匹配,就执行一系列指令。该实用工具扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式。如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行。

在我们的Linux中,awk其实是gawk的一个软连接,所以我们所使用的都是GNU AWK

awk的运行方式:

         (1) awk命令行

                   # awk

         (2) awk程序文件

                   # awk -f /path/from/awk_script

         (3) awk脚本

扫描二维码关注公众号,回复: 2540338 查看本文章

                   #!/bin/awk –f

Awk在处理文本时会将每一行读取到自己的内存空间当中,并将每一行文本根据我们制定的分隔符等分成不同的区域,类似脚本的内置位置变量。在处理完之后,输出时awk依然是按照一行来输出的,即便是输出的内容不是原来的一整行,输出的分割符默认为空格,也可以自定义。

基本用法:

         gawk [OPTIONS] 'program' FILE1 FILE2 ...

                   program: PATTERN{ACTION STATEMENT}

                            由语句组成,各语句间使用分号分隔;

                            ACTION: print, printf

         选项:

                   -F[]: 指明输入字段分隔符,可以是多个,例:-F [:,]即用:当分隔符又用,当分隔符;

                   -v VAR_NAME=VALUE: 变量赋值;

                   -f /PATH/FROM/AWK_SCRIPT

1awk的输出命令之一:print

                   用法:print item1, item2, ...

                            item

                                     字符串:用引号引用;

                                               print "hello", "world"

                                     变量:显示变量的值;

                                               print name

                                               引用变量:直接使用变量名

                                     数值:无须加引号

                   要点:

                            (1) item之间需要使用逗号分隔;而输出时的分隔符为默认为空白字符;

                            (2) 输出的各item可以为字符串或数值、当前记录的字段($#)、变量或awk的表达式;数值会被隐式转换为字符串进行输出;

                            (3) print后面的item省略时,相当于运行“print $0”,用于输出整行;

                            (4) 输出空白字符:print " "

2、变量

         内建变量,自定义变量

2.1 内置变量

AWK的内建变量包括域变量,例如$1, $2, $3,以及$0。这些变量给出了记录中域的内容。 内建变量也包括一些其他变量:

NR:已输入记录的条数。

FNR:行数,各文件单独计数。

NF:当前记录中域的个数。记录中最后一个域可以以$NF的方式引用。print NF  每行有几个字段,print $NF  显示每一行的最后一个字段

FILENAME:当前输入文件的文件名。

FS:“域分隔符”,用于将输入记录分割成域。其默认值为“空白字符”,即空格和制表符。FS可以替换为其它字符,从而改变域分隔符。-v FS="[ ,:.]"

RS:当前的“记录分隔符”。默认状态下,输入的每行都被作为一个记录,因此默认记录分隔符是换行符。

OFS:“输出域分隔符”,即分隔print命令的参数的符号。其默认值为空格。

ORS:“输出记录分隔符”,即每个print命令之间的符号。其默认值为换行符。

OFMT:“输出数字格式”(Format for numeric output),其默认值为"%.6g"

ARGCawk命令行中的参数的个数。

ARGV:数组,保存了命令行参数本身。

2.2 自定义变量

         (1) -v VAR_NAME=VALUE

                   变量名区分字符大小写;

         (2) program中自定义变量

                   # awk 'BEGIN{FS=":";f1=3}{print $f1}' /etc/passwd

f1赋值一次一直使用

每读取一行f1赋一次值

3awk的输出命令之二:printf

         语法:printf FORMAT(格式),item1,item2,...

         要点:

                   (1) 必须提供FORMAT

                   (2) print语句不同,printf不会自动换行,需要显式指定换行符:\n

                   (3) FORMAT中需要分别为后面的每个item指定一个格式符,否则item则无法显示;   

         格式符:都以%开头,后跟单个字符;

                   %c: 显示字符的ASCII码;

                   %d, %i:显示为十进制整数;

                   %e, %E: 科学计数法显示数值;

                   %f:显示为浮点数;

                   %g, %G:以科学计数法或浮点数格式显示数值;

                   %s: 显示为字符串;

                   %u:显示无符号整数;

                   %%: 显示%符号自身;

         修饰符:

                   #[.#]

                            左边的#:用于指定显示宽度;

                            右边的#: 显示精度;

                   +:显示数值符号

                   -:左对齐

4、操作符

         算术操作符:

                   x+y, x-y, x*y, x/y, x^y, x%y

                   -x: 负值

                   +x: 转换为数值

         字符操作符:字符串连接

         赋值操作符:

                   =, +=, -=, *=, /=, %=, ^=

                   ++, --

         比较操作符:

                   >, >=, <, <=, ==, !=

         模式匹配操作符:

                   ~:是否能由右侧指定的模式所匹配;

                   !~:是否不能由右侧指定模式所匹配;

         逻辑操作符:

                   &&:与运算

                   ||: 或运算

         条件表达式:

                   selector?if-true-expression:if-false-expression

                   # awk -F: '{$3>=500?usertype="Common User":usertype="Sysadmin or Sysuser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd

         函数调用:

                   function_name(argu1, argu2, ...)

5PATTERN模式

(1)    empty:空模式,匹配所有行;

         (2) /Regular Expression/(正则表达式):仅将ACTION应用于能够被Regular Expression所匹配到的行;

                   例如:awk -F: '/^[ab]/{print $1,$3}' /etc/passwd

         (3) relational expression:关系表达式,即结果为“真”、“假”的表达式, 或者其结果能类同于“真”或“假”的表达;一般来说,其结果为非0数值或非空字符串即可类同为“真”,否则,则类同为“假”;

                   例如:awk -F: '$3>=500{print $1,$3}' /etc/passwd

                   例如:awk -F: '$1~/root/{print $1,$3}' /etc/passwd

         (4) line ranges:行范围,类似sedvim中的地址定界方式

                   startline,endline

                   此方式我没有试验成功,待定

         (5) BEGIN/END:两个特殊模式

                   BEGIN:在文件格式化操作开始之前事先执行的一次操作;通常用于输出表头或做出一个预处理操作;

                   END:在文件格式操作完成之后,命令退出之前执行的一次操作;通常用于输出表尾或做出清理操作;

6、常用ACTION

         (1) EXPRESSIONS:例如变量赋值

         (2) Control Statements:控制语句,如if, while等;

         (3) Compound Statements:复合语句

         (4) input statements:输入语句

         (5) output statements:输出语句

7、控制语句

         if (condition) { statements } [else { statement }]

         while (condition) { statements }

         do statement while (condition)

         for(expr1;expr2;expr3) { statements }

         for(var in array) { statements }

         switch (expression) {case VALUE or /REGEXP/: statement; ...; default: statementN}

         break

         continue

         delete array[index]

         delete array

         exit [ expression ]

         { statements }

 

         7.1 if-else

                   语法:if (condition) statement [ else statement ]

                            if (condition) {statements} [else {statements}]

                                               ~]# awk -F: '{if ($3>=500) print $1,$3}' /etc/passwd

                                               ~]# awk '{if (NF>=6) print NF,$0}' /etc/rc.d/rc.sysinit

                                               ~]# awk -F: '{if ($3>=500) {print $1,"is a common user"} else {print $1,"is a sysadmin or sysuser"}}' /etc/passwd

使用场景:对awk取得的整行或行中的字段做条件判断;

         7.2 while循环

                   语法:while (condition) statement

                            while (condition) {statements}

                            条件为“真”时循环,为“假”时退出循环;

                   使用场景:通常用于在当前行的各字段间进行循环;

                   ~]# awk '{i=1;while(i<=NF){if (length($i)>=6) {print $i};i++}}' /etc/issue

         7.3 do-while循环

                   语法:do statement while (condition)

                            do {statements} while (condtion)

                            意义:至少执行一次循环体

         7.4 for循环

                   语法:for (expr1;expr2;expr3) statement

                            for (expr1;expr2;expr3) {statements}

                   for (variable assignment;codition;iteration process) {for-body}

                   # awk '{for(i=1;i<=NF;i++){if(length($i)>=6) print $i}}' /etc/issue

                   第二种用法:用于遍历数组中的元素

                            for (var_name in array) {for-body}

         7.5 swtich

                   语法:switch (expression) {case VALUE or /REGEXP/: statement; ...; default: statementN}

         7.6 break and continue

                   break [n]:退出当前循环,n是一个数字,用于指定退出几层循环;

                   continue:提前结束本轮循环而进入下一轮;

         7.7 next

                   提前结束对本行文本的处理,而提前进入下一行的处理操作;

                   ~]# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd

8、数组

         关联数组:array[index-expression]

                   index-expression

                            可以使用任意字符;

                            如果某数组元素事先不存在,则在引用时,awk会自动创建此元素并将其值初始化为空串;

                                     因此,若要判断 数组中的某元素是否存在,要使用“index in array”的方式进行判断;

                            要遍历数组中的元素,则要使用for (var_name in array)的方式进行;此时,var_name会遍历array的每个索引,所以,要显示数组元素的值,要使用array[var_name]

                   weekdays

                            weekdays[mon]="Monday"

                            weekdays[tue]="Tuesday"

                            ...

                   for (i in weekdays):此时,i变量会遍历weekdays数组的每个索引,即mon, tue,而非元素的值“Monday”或"Tuesday"等;

                   要获取元素的值:weekdays[i]

9、函数

         内建函数和用户自定义函数

      9.1 内建函数

                   数值处理:

                            rand():返回01之间的一个随机数;

                   字符串处理:

                            length([s]):返回指定的字符串的长度;

                            sub(r,s[,t]):基于r所表示的模式来匹配字符串t中的内容,将其第一次被匹配到的内容替换为s所表示的字符串;

gsub(r,s[,t]):基于r所表示的模式来匹配字符串t中的内容,将其所有被匹配到的内容均替换为s所表示的字符串;

                            split(s,a[,r]):以r为分隔符去切割字符串s,并将切割后的结果保存至a表示的数组中;

                                     注意:awk的数组下标从1开始编号

                                     ~]# awk '{split($0,userinfo,":");print userinfo[1]}' /etc/passwd

                            substr(s,i[,n]):从s所表示的字符串中取子串,取法:从i表示的位置开始,取n个字符;

                   时间类函数:

                            systime():取当前系统时间,结果形式为时间戳;

      9.2 用户自定义函数

                   function f_name(p,q) {

                            ...

                   }


猜你喜欢

转载自blog.51cto.com/13869667/2154334