一、介绍
   awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是 linux/unix 下的一个强大编程工具。它在命令行中使用, 但更多是作为脚本来使用。
   awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。可以看出,sed 常常作用于一整个行的处理, awk 则比较倾向于一行当中分成数个“字段”来处理。

二、调用方式
三种方式调用 awk

1) awk [opion] 'awk_script' input_file1 [input_file2 ...]

awk 的常用选项 option 有:

  ① -F fs:使用fs作为输入记录的字段分隔符,如果省略该选项,awk使用空格作为缺省的域分割符。

  ② -f filename  : 从文件 filename 中读取awk脚本

  ③ -v var=value : 为 awk_script 设置变量

2) 将awk脚本放入脚本文件并以 #!/bin/awk -f 作为首行,给予该脚本可执行权限,然后在 shell 下通过键入该脚本的脚本名调用之。

3) 将所有的awk命令插入一个单独文件,然后调用:awk -f awk-script-file input-file(s)

   -f 选项指明在文件awk_script_file中的awk脚本,input_file(s)是使用awk进行浏览的文件名

三、awk基础
1. awk脚本的组成:

 ① awk脚本可以由一条或多条awk命令组成,两条awk命令之间一般以新行分隔

 ② awk命令由两部分组成:  awk_pattern { actions }

 ③ awk脚本可以被分成多行书写,必须确保整个awk脚本被单引号括起来。

2.awk 命令的一般形式:

  awk ' BEGIN { actions }          \

        awk_pattern1 { actions }    \

        ............                 >  awk_script

        awk_patternN { actions }    /  



        END { actions }            /

      ' inputfile          

说明:

 a)BEGIN { actions }和 END { actions }是可选的;

 b)iput_file 可以是多于一个文件的文件列表,awk 将按顺序处理列表中的每个文件。

 c)BEGIN 区块和 END 区块别位于awk脚本的开头和结尾。awk脚本中只有END区块或者只有BEGIN区块是被允许的。如果 awk_script 中只有 BEGIN { actions } ,awk 不会读取 input_file。

 d)awk 把输入文件的数据读入内存,然后操作内存中的输入数据副本,awk 不会修改输入文件的内容。

 e)awk 的总是输出到标准输出,如果想让awk输出到文件,可以使用重定向。

 f)一条awk命令的 awk_pattern可以省略,省略时不对输入记录进行匹配比较就执行相应的动作。一条awk命令的actions也可以省略,省略时默认的动作为打印当前输入记录(print $0) 。一条 awk_cmd 中的 awk_pattern 和 actions 不能同时省略。

3.awk 的运行过程:

 a)如果 BEGIN 区块存在,awk 执行它指定的 actions。

 b)awk 从输入文件中读取一行,称为一条输入记录。(如果输入文件省略,将从标准输入读取)

 c)awk 将读入的记录分割成字段,将第 1 个字段放入变量$1 中,第 2 个字段放入$2,以此类推。$0 表示整 条记录。字段分隔符使用 shell 环境变量 IFS 或由参数指定。

 d)把当前输入记录依次与每一个awk命令中的pattern比较,看是否匹配,如果相匹配,就执行对应actions。如果不匹配,就跳过对应的actions,直到比较完所有的 awk命令。

 e)当一条输入记录比较了所有的awk命令后,awk 读取输入的下一行,继续重复步骤c和步骤d,这个过程一直持续,直到awk读取到文件尾。

 f)当 awk 读完所有的输入行后,如果存在 END,就执行相应的 actions。

四、域与记录
1.记录

 awk默认把每一个以换行符结束的行称为一个记录。

 记录分隔符:默认的输入和输出的分隔符都是回车,保存在内建变量ORS和RS中。

 $0变量:它指的是整条记录。如$ awk '{print $0}' test将输出test文件中的所有记录。

 变量NR:一个计数器,每处理完一条记录,NR的值就增加1。如$ awk '{print NR,$0}'  test将输出test文件中所有记录,并在记录前显示记录号。

2.域

 记录中每个单词称做“域”,默认情况下以空格或tab分隔。awk可跟踪域的个数,并在内建变量NF中保存该值。如$ awk '{print $1,$3}' test将打印test文件中第一和第三个以空格分开的列(域)。

 ※通过-F指定,可以改变域的分隔符。

3.域的分隔符

 a)输入域的分隔符

   内建变量FS保存输入域分隔符的值,默认是空格或tab。我们可以通过-F命令行选项修改FS的值。如$ awk -F: '{print $1,$5}' test将打印以冒号为分隔符的第一,第五列的内容。

   也可以通过在BEGIN中重新定义NF变量实现类似的目的,如awk 'BEGIN {FS = ":"}  {print $1,$2}' test。(awk中,字符串都应该用""号括起)

   也可以同时使用多个域分隔符,这时应该把分隔符写成放到方括号中,如$awk  -F'[:\t]' '{print $1,$3}' test,表示以空格、冒号和tab作为分隔符。

  b)输出域的分隔符

   默认是一个空格,保存在OFS中。如$ awk -F: '{print $1,$5}' test,$1和$5间的逗号就是OFS的值。

五、awk_pattern
awk_pattern 模式部分决定actions动作部分何时触发及触发actions。awk_pattern 可以是以下几种类型:

 1. 正则表达式用作 awk_pattern: /regexp/

  awk 中正则表达式匹配操作中经常用到的字符:

    \  ^  $  .  []   |   ()    *    // 通用的 regexp 元字符

    + : 匹配其前的单个字符一次以上,是awk自有的元字符,不适用于grep或sed等

    ?:匹配其前的单个字符 1 次或 0 次,是 awk 自有的元字符,不适用于 grep 或 sed 等
   举例:  awk '/ *\$0\.[0-9][0-9].*/' input_file

  2. 布尔表达式用作awk_pattern,表达式成立时,触发相应的actions执行。

   1) 表达式中可以使用变量(如字段变量$1,$2 等)和/regexp/

   2) 布尔表达式中的操作符:

  关系操作符: <   >    <=    >=      !=      

  匹配操作符: value ~ /regexp/        如果 value 匹配/regexp/,则返回真

                value !~ /regexp/       如果 value 不匹配/regexp/,则返回真

  举例: awk '$2 > 10 {print "ok"}' input_file

        awk '$3 ~ /^d/ {print "ok"}' input_file

  3)&&(与) 和 ||(或) 可以连接两个/regexp/或者布尔表达式,构成混合表达式。!(非) 可以用于布尔表达式或者 /regexp/之前。

    举例: awk '($1 < 10 ) && ($2 > 10) {print "ok"}' input_file  

          awk '/^d/ || /x$/ {print "ok"}' input_file

   4) 其它表达式用作awk_script,如赋值表达式等

    举例:

    awk '(tot+=$6); END{print "total points :" tot }' input_file// 分号不能省略

    awk 'tot+=$6 {print $0} END{print "total points :" tot }' input_file // 与上面等效





awk条件操作符

操作符

描述

操作符

描述

<

小于

> =

大于等于

< =

小于等于

~

匹配正则表达式

==

等于

!~

不匹配正则表达式

!=

不等于







awk的运算符

     运算符

     描述

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

     赋值

||

      逻辑或

&&

      逻辑与

~ ~!

匹配正则表达式和不匹配正则表达式

< <= > >= !=

关系运算符

空格

连接

+ -

加,减

* / &

乘,除与求余

+ - !

一元加,减和逻辑非

^ ***

求幂

++ --

增加或减少,作为前缀或后缀

$

字段引用

in

数组成员

六、actions
   actions就是对awk读取的记录数据进行的操作。actions 由一条或多条语句或者命令组成,语句、命令之间用分号(;)分隔。actions中还可以使用流程控制结构的语句。

  1. awk 的命令:

    1)print 参数列表:print 可以打印字符串(加双引号)、变量和表达式,是awk最基本的命令。参数列表要用逗 号(,)分隔,如果参数间用空格分隔,打印出时参数值之间不会有空格。

    2)printf ([格式控制符],参数) : 格式化打印命令(函数),语法与 C 语言的 printf 函数类似。

awk printf格式

% c

A S C I I字符

% d

整数

% e

浮点数,科学记数法

% f

浮点数,例如(1 2 3 . 4 4)

% g

awk决定使用哪种浮点数转换e或者f

% o

八进制数

% s

字符串

% x

十六进制数



     3)next:强迫awk立刻停止处理当前的记录,而开始读取和处理下一条记录。

     4)nextfile:强迫awk立刻停止处理当前的输入文件而处理输入文件列表中的下一个文件

     5)exit : 使awk停止执行而跳出。如果有END存在,awk会去执行END的actions。

 2.awk的语句:awk的语句主要是赋值语句,用来给变量赋值。

     1)把直接值或一个变量值赋值给变量。如果直接值是字符串要加双引号。

       举例: awk 'BEGIN {x=1 ; y=3 ; x=y ; print "x=" x " ; y=" y" }'

     2)把一个表达式的值赋值给变量。表达式一般是数值表达式,也可以是其它表达式。

       数值表达式: num1 operator num2

       operator 可以是: +(加)  -(减)  *(乘)  /(除)  %(取模)  ^(求幂)

       当num1或者num2是字符串而是不是数字时,无论是否加有双引号,awk 都视其值为 0

       条件选择表达式: A?B:C  (A为布尔表达式,B 和 C 可以是表达式或者直接值) 当布尔表达式A的值为真时,整个表达式的值为B,A的值为假时,整个表达式的值为 C

      举例: awk 'BEGIN {x=3 ; x+=2 ; y=x+2 ; print "x=" x " ; y=" y }'

            awk 'BEGIN {x=3 ; y=x>4?"ok":4 ; print "x=" x " ; y=" y }'

    3)为了方便书写,awk也支持C语言语法的赋值操作符: +=  -=  *=  /= %=  ^=   ++  --

3. 流程控制结构 (基本上是使用 C 语言的语法)

   其中condition一般为布尔表达式,body和else-body是awk语句块。

    1)if (condition) {then-body} [else {else-body}]

    2)while (condition) {body}

    3)do {body} while (condition)

    4)for (initialization; condition; increment) {body} 与C语言的 for 结构的语法相同。

    5)break: 跳出包含它的 for、while、do-while 循环

    6)continue: 跳过 for、while、do-while 循环的 body 的剩余部分,而立刻进行下一次循环的执行

4. 字符串屏蔽序列

  使用字符串或正则表达式时,有时需要在输出中加入一新行或查询一元字符。

  打印一新行时,(新行为字符\ n),给出其屏蔽序列,以不失其特殊含义,用法为在字符串前加入反斜线。例如使用\ n强迫打印一新行。 如果使用正则表达式,查询花括号({ }),在字符前加反斜线,如/ \ { / ,将在awk 中失掉其特殊含义。

awk中使用的屏蔽序列

\ b     退格键

\ t        tab键

\ f      走纸换页

\ d d d    八进制值

\ n      新行

\ c        任意其他特殊字符,例如\ \为反斜线符号

\ r      回车键





七、awk 内部编程

    awk 内部有大量的函数和变量可以使用 C 语言的方式引用,但此涉及的范围非常广,日常中一般用到的不多,这里只举例说明常用的。

1. BEGIN 模块

   BEGIN 模块后紧跟着动作块,这个动作块在awk处理任何输入文件之前执行。所以它可以在没有任何输入的情况下进行测试。它通常用来改变内建变量的值,如:OFS,RS和FS等,以及打印标题。

   $ awk 'BEGIN{FS=":"; OFS="\t"; ORS="\n\n"}{print $1,$2,$3} ' test。

  上式表示,在处理输入文件以前,域分隔符(FS)被设为冒号,输出文件分隔符(OFS)被设置为制表符,输出记录分隔符(ORS)被设置为两个换行符。

   $ awk 'BEGIN{print "TITLE TEST"} '

   只打印标题

   ※ 使用BEGIN,可以忽略files指定。

2.END 模块

   END不匹配任何的输入文件,但是执行动作块中的所有动作,它在整个输入文件处理完成后被执行。

   $ awk 'END{print "The number of records is" NR}' test

   上式输出的最后,打印所有被处理的记录数。

3.重定向和管道

  awk也可使用shell的重定向符进行重定向输出

  $ awk '$1 = 100 {print $1 > "output_file" }' test

 上式表示如果第一个域的值等于100,则把它输出到output_file中。也可以用>>来重定向输出,但不清空文件,只做追加操作。

  输出重定向需用到 getline 函数。getline 从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给 NF,NR和 FNR 等内建变量赋值。如果得到一条记录,getline 函数返回 1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,就返回-1。

  $ awk 'BEGIN{ "date" | getline d; print d}' test

  执行linux的date命令,并通过管道输出给getline,然后再把输出赋值给自定义变量 d,并打印它。

  $ awk 'BEGIN{"date" | getline d; split(d,mon); print mon[2]}' test

  执行shell的date命令,并通过管道输出给getline,然后getline从管道中读取并将 输入赋值给d,split函数把变量d转化成数组mon,然后打印数组mon的第二个元素。

  $ awk 'BEGIN{while( "ls" | getline) print}'

  命令ls的输出传递给geline作为输入,循环使getline从ls的输出中读取一行,并把它打印到屏幕。这里没有输入文件,因为BEGIN块在打开输入文件前执行,所以可以忽略输入文件。

 $ awk 'BEGIN{printf "What is your name?"; getline name < "/dev/tty" } $1 ~name {print "Found" name on line ", NR "."} END{print "See you," name "."} test

 在屏幕上打印”What is your name?",并等待用户应答。当一行输入完毕后,getline函数从终端接收该行输入,并把它储存在自定义变量name中。如果第一个域匹配变量name的值,print函数就被执行,END块打印See you和name的值。

  $ awk 'BEGIN{while (getline < "/etc/passwd" > 0) lc++; print lc}'

  awk将逐行读取文件/etc/passwd的内容,在到达文件末尾前,计数器lc一直增加,当到末尾时,打印lc的值。注意,如果文件不存在,getline返回-1,如果到达文件的末尾就返回0,如果读到一行,就返回1,所以命令 while (getline < "/etc/passwd") 在文件不存在的情况下将陷入无限循环,因为返回-1表示逻辑真。

   可以在 awk 中打开一个管道,且同一时刻只能有一个管道存在。通过 close()可关闭管道。

  $ awk '{print $1, $2 | "sort" }' test END {close("sort")}

 awk把print语句的输出通过管道作为linux命令sort的输入,END块执行关闭管道操作。

  system函数可以在awk中执行linux的命令

  $ awk 'BEGIN{system("clear")}'

4.条件语句

  $ awk '{if ($1 <$2) print $2 "too high"}' test

  如果第一个域小于第二个域则打印。

  $ awk '{if ($1 < $2) {count++; print "ok"}}' test

  如果第一个域小于第二个域,则count加一,并打印ok。

  $ awk '{if ($1 > 100) print $1 "bad" ; else print "ok"}' test

  如果$1大于100则打印$1 bad,否则打印ok。

  $ awk '{if ($1 > 100){ count++; print $1} else {count--; print $2}' test

  如果$1大于100,则count加一,并打印$1,否则count减一,并打印$1。

  $ awk '{ i = 1; while ( i <= NF ) { print NF,$i; i++}}' test

  变量的初始值为1,若i小于可等于NF(记录中域的个数),则执行打印语句,且i增加1。 直到i的值大于NF.

  $ awk '{for (i = 1; i<NF; i++) print NF,$i}' test

  作用同上。

5.数组

  用变量作为数组下标

  $ awk {name[x++]=$2};END{for(i=0;i<NR;i++) print i,name[i]}' test

  数组name中的下标是一个自定义变量x,awk初始化x的值为0,在每次使用后增加1。 第二个域的值被赋给name数组的各个元素。在END模块中,for循环被用于循环整个数组,从下标为0的元素开始,打印那些存储在数组中的值。因为下标是关健字,所以它不一定从0开始,可以从任何值开始。

   special for循环用于读取关联数组中的元素。格式如下:

{for (item in arrayname){

        print arrayname[item]

        }

}

 $ awk '/^tom/{name[NR]=$1}; END{for(i in name){print name[i]}}' test

 打印有值的数组元素。打印的顺序是随机的。 用字符串作为下标,如:count["test"]。  用域值作为数组的下标。

 一种新的for循环方式:for (index_value in array) statement。

 $ awk '{count[$1]++} END{for(name in count) print name,count[name]}' test

 该语句将打印$1中字符串出现的次数。它首先以第一个域作数组count的下标,第一个域变化,索引就变化。

   delete函数用于删除数组元素

  $ awk '{line[x++]=$1} END{for(x in line) delete(line[x])}' test

 分配给数组line的是第一个域的值,所有记录处理完成后,special for循环将删除每一个元素。

 对于记录“123#456#678”,先使用split函数划分它,再使用循环打印各数组元素。操作脚本如下:

 $vi arraytest.awk

 #!/bin/awk –f

 BEGIN{

  record=“123#456#678”;

  split(record,myarray,“#”)}

   END{ for(i in myarray) {print myarray[i]}}

 要运行脚本,使用/ d e v / n u l l作为输入文件。

 $arraytest.awk  /dev/null

 123

 456

 789

八、awk 的变量
 在awk脚本中的表达式中要经常使用变量。不要给变量加双引号,那样做,awk 将视之为字符串。awk 的变量基本可以分为两类:

1.awk 内部变量: awk 的内部变量用于存储 awk 运行时的各种参数,这些内部变量又可以分为:

 1)自动内部变量: 这些变量的值会随着awk程序的运行而动态的变化,在awk脚本中改变这些变量的值是没有意义的(即不应该被赋值)。常见的有:

    NF: 当前输入字段的字段数

    NR: 对当前输入文件而言,已经被awk读取过的记录(行)的数目。

    FNR:已经被awk读取过的记录(行)的总数目。当输入文件只有一个时,FNR和NR是一致的。

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

    ARGC: 命令行参数个数。(不包括选项和awk脚本,实际就是输入文件的数目加 1)

    ARGIND: 当前被处理的文件在数组ARGV内的索引( 实际上 ARGV[1]就是第一个输入文件 )

 2)字段变量($0$1$2$3 ...): 当awk把当前输入记录分段时,会对这些字段变量赋值。和内部变量类似,在awk运行过程中字段变量的值是动态变化的。不同的是,修改这些字段变量的值是有意义的,被修改的字段值可以反映到 awk 的输出中。

   可以创建新的输出字段,比如,当前输入记录被分割为8个字段,这时可以通过对变量$9 (或$9 之后的字段变量)赋值而增加输出字段,NR 的值也将随之变化。

  字段变量支持变量名替换。

3) 其它内部变量: 可以修改这些变量。常见的有:

      FS: 输入记录的字段分隔符(默认是空格和制表符)

      OFS: 输出记录的字段分隔符(默认是空格)

      OFMT: 数字的输出格式(默认是 %.6g)

      RS: 输入记录间的分隔符(默认是 NEWLINE)

      ORS: 输出记录间的分隔符(默认是 NEWLINE)

      ARGV: 命令行参数数组

      ENVIRON: 存储系统当前环境变量值的数组,它的每个成员的索引就是一个环境变量名,而对应的值就是相应环境变量的值。可以通过给 ENVIRON 数组的成员赋值而改变环境变量的值,但是新值只在 awk_script 内有效。eg: ENVIRON["HISTSIZE"]=500

2.自定义变量

 1)定义变量: varname=value (自定义变量不需先声明后使用,赋值语句同时完成变量定义和初始化)

 2)在表达式中出现不带双引号的字符串都被视为变量,如果之前未被赋值,默认值为 0 或空字符串。

 3)向命令行 awk 程序传递变量的值:

   a)Usage: awk 'awk_script' awkvar1=value1 awkvar2=value2 ....  input_file

   b)awkvar 可以是 awk 内置变量或自定义变量。

   c)awkvar 的值将在 awk 开始对输入文件的第一条记录应用 awk_script 前传入。如果在 awk_script 中已经对某个变量赋值,那么在命令行上传人到该变量的值就会无效(实际上是 awk_script 中的赋值语句覆盖了从命令行上传入的值)。

   d)在 awk 脚本程序中不能直接使用shell的变量。通过使用下面的语法可达到这样的效果。

    awk 'awk_script' awkvar1=shellvar1 awkvar2=shellvar2 ....  input_file

    eg: awk '{if (v1   "root") {print "User name is root!"}}' v1=$USER input_file

   e) 可以向awk脚本传递变量的值,与上面的类似。

      awk_script_file awkvar1=value1 awkvar2=value2 ... input_file

九、awk 的内置函数
  可以在awk脚本的任何地方使用 awk 函数。和awk变量一样,awk 函数可以分为内置函数和自定义函数。

  1. 常见awk内置数值函数

  int(x): 求出 x 的整数部份,朝向 0 的方向做舍去。eg: int(3.9)是 3,int(-3.9) 是-3。

  sqrt(x): 求出 x 正的平方根值。eg: sqrt(4)=2

  exp(x): 求出 x 的次方。eg: exp(2) 即是求 e*e 。

  log(x): 求出 x 的自然对数。

  sin(x): 求出 x 的 sine 值,x 是弪度量。

  cos(x): 求出 x 的 cosine 值,x 是弪度量。

  atan2(y,x):  求 y/x 的 arctangent 值,所求出的值其单位是弪度量。

  rand(): 得到一个随机数(平均分布在 0 和 1 之间)。每次执行 gawk,rand 从相同的 seed 生成值。

  srand(x): 设定产生随机数的 seed 为 x。如果在第二次运行 awk 程序时你设定相同的 seed 值,你将再度 得到相同序列的随机数。如果省略引数 x,例如 srand(),则当前日期时间会被当成 seed。这个方法可使得随机数值是真正不可预测的。

  srand(): 其值是当次 awk_script 运行过程中前次 srand(x)的设定的 seed 值 x,。                  

  2.常见 awk 内置字符串函数

  index(in, find) : 返回字符串 in 中字符串 find 第一次出现的位置(索引从 1 开始),如果在字串 in 中找不到字符串 find,则返回值为 0。eg: print index("peanut","an") 会印出 3。

  length(s)  : 求出字符串 s 的字符个数。eg: length("abcde") 是 5。

  match(s,r) : 返回模式字符串 r 在字符串 s 的第一次出现的位置,如果 s 不包含 r,则返回值 0。

  sprintf(fmt,exp1,...)  : 和 printf 类似印出,是 sprintf 不是打印而是返回经 fmt 格式化后的 exp。

    eg: sprintf("pi = %.2f (approx.)",22/7) 传回的字串为"pi = 3.14 (approx.)"

  sub(p, r,t) : 在字符串 t 中寻找符合模式字符串 p 的最靠前最长的位置,并以字符串 r 代替最前的p

    eg: str = "water, water"sub(/at/, "ith",str) 结果字符串 str 会变成"wither, water"

  gsub(p, r, t) : gsub 与 sub 类似。不过时在字符串 t 中以字符串 r 代替所有的 p。

    eg: str="water, water" ; gsub(/at/, "ith",str) 结果字符串 str 会变成"wither,wither"

  substr(str, st, len)  : 传回 str 的子字符串,其长度为 len 字符,从 str 的第 st 个位置开始。如果 len 没有出现,则传回的子字符串是从第 st 个位置开始至结束。

    eg: substr("washington",5,3) 传回值为"ing"

        substr("washington",5)   传回值为"ington"

  split(s,a,fs) : 在分隔符 fs 为分隔符将字符串 s 分隔成一个 awk 数组 a,并返回 a 的下标数。    

    eg: awk 'BEGIN{print split("123#456#789",myarray,"#")}' 将打 印 3 。

  tolower(str)  : 将字符串 str 的大写字母改为小写字母。

    eg: tolower("MiXeD cAsE 123") 传回值为"mixed case 123"

  toupper(str)  : 将字符串 string 的小写字母改为大写字母。

    eg: toupper("MiXeD cAsE 123")传回值为"MIXED CASE 123"

 3.常见 awk 内置系统函数

  close(filename) : 将输入或输出的文件 filename 关闭。

  system(command) : 此函数允许调用操作系统的指令,执行完毕後将回到 awk 程序。

    eg: awk 'BEGIN {system("ls")}'

十、自定义函数

 复杂的 awk 常常可以使用自己定义的函数来简化。调用自定义的函数与调用内置函数的方法一样。

  1) 自定义函数定义的格式: 自定义函数可以在 awk 程序的任何地方定义。

   function fun_name (parameter_list) {    // parameter_list 是以逗号分隔的参数列表

   body-of-function                // 函数体,是 awk 语句块

  2) 举例:

   awk '{ print "sum =",SquareSum($1,$2) }

      function SquareSum(x,y) { sum x*x+y*y ; return sum } ' grade.txt

十一、其他

 1) 为了避免碰到awk错误,可以总结出以下规律:

  ① 确保整个awk_script 用单引号括起来。

  ② 确保awk_script内所有引号成对出现。

  ③ 确保用花括号括起动作语句,用圆括号括起条件语句。

  ④ 可能忘记使用花括号,也许你认为没有必要,但 awk 不这样认为,将按之解释语法。

  ⑤ 如果使用字符串,一定要保证字符串被双引号括起来(在模式中除外)。

 2) 在awk中,设置有意义的域名是一种好习惯,在进行模式匹配或关系操作时更容易理解。一般的变量名设置方式为 name=$n。(这里name为调用的域变量名,n为实际域号。)

 3) 通常在BEGIN部分给一些变量赋值是很有益的,这样可以在awk表达式进行改动时减少很多麻烦。

 4) awk的基本功能是根据指定规则抽取输入数据的部分内容并输出,另一个重要的功能是对输入数据进行分析运算得到新的数据并输出,这是通过在awk脚本中对字段变量($1、$2、$3...)从新赋值或使用更大的字段变量$n(n 大于当前记录的 NF)而实现的。

 5) 使用字符串或正则表达式时,有时需要在输出中加入一新行或查询一元字符。这时就需要字符串屏蔽序列。

 awk 中经常使用的屏蔽序列有:

 \b 退格键          \t tab 键 \f 走纸换页       \ddd 八进制值      \n 新行           \r 回车键             \c 任意其他特殊字符。eg: \\为反斜线符号

6) awk的输出函数 printf,基本上和 C 语言的语法类似。

 ① 格式: printf("输出模板字符串",参数列表)

 ② 参数列表是以逗号分隔的列表,参数可以是变量、数字值或字符串。

 ③ 输出模板字符串的字符串中必须包含格式控制符,有几个参数就要求有几个格式控制符。模板字符串中可以只有格式控制符而没有其它字符。

④ 格式控制符:  %[-][width][.prec]fmt

     %          : 标识一个格式控制符的开始,不可省略。

     -          : 表示参数输出时左对齐,可省略。

width      : 一个数字,表示参数输出时占用域的宽度,可省略。

     .prec      : prec 是一个数值,表示最大字符串长度或小数点右边的位数,可省略。

     fmt        : 一个小写字母,表示输出参数的数据类型,不可省略。

⑤ 常见的 fmt : c ASCII 字符

              d 整数  

              e 浮点数,科学记数法  

              f 浮点数,如 123.44

              g 由 awk 决定使用哪种浮点数转换 e 或 f                  

              o 八进制数    

              s 字符串

              x 十六进制数

⑥ 举例: echo "65" | awk '{ printf ("%c\n",$0) }'  // 将打印 A

  awk 'BEGIN{printf "%.4f\n",999}'                //将打印 999.0000

  awk 'BEGIN{printf "2 number:%8.4f%8.2f",999,888}'  // 将打印 2 number:999.0000 888.000